Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 208d7638c9 | |||
| 26a74a9269 | |||
| ffa6692e07 | |||
| 44690f8e9d | |||
| 9aa9d5ab03 | |||
|
|
88ff621f22 |
@@ -1,25 +0,0 @@
|
|||||||
**/.dockerignore
|
|
||||||
**/.env
|
|
||||||
**/.git
|
|
||||||
**/.gitignore
|
|
||||||
**/.project
|
|
||||||
**/.settings
|
|
||||||
**/.toolstarget
|
|
||||||
**/.vs
|
|
||||||
**/.vscode
|
|
||||||
**/.idea
|
|
||||||
**/*.*proj.user
|
|
||||||
**/*.dbmdl
|
|
||||||
**/*.jfm
|
|
||||||
**/azds.yaml
|
|
||||||
**/bin
|
|
||||||
**/charts
|
|
||||||
**/docker-compose*
|
|
||||||
**/Dockerfile*
|
|
||||||
**/node_modules
|
|
||||||
**/npm-debug.log
|
|
||||||
**/obj
|
|
||||||
**/secrets.dev.yaml
|
|
||||||
**/values.dev.yaml
|
|
||||||
LICENSE
|
|
||||||
README.md
|
|
||||||
102
.gitignore
vendored
102
.gitignore
vendored
@@ -29,8 +29,10 @@ x86/
|
|||||||
bld/
|
bld/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
[Ll]og/
|
[Ll]og/
|
||||||
[Ll]ogs/
|
[Ll]ogs/
|
||||||
|
[Dd]ata/
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
@@ -62,9 +64,6 @@ project.lock.json
|
|||||||
project.fragment.lock.json
|
project.fragment.lock.json
|
||||||
artifacts/
|
artifacts/
|
||||||
|
|
||||||
# Tye
|
|
||||||
.tye/
|
|
||||||
|
|
||||||
# ASP.NET Scaffolding
|
# ASP.NET Scaffolding
|
||||||
ScaffoldingReadMe.txt
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
@@ -363,100 +362,3 @@ MigrationBackup/
|
|||||||
|
|
||||||
# Fody - auto-generated XML schema
|
# Fody - auto-generated XML schema
|
||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
|
|
||||||
##
|
|
||||||
## Visual studio for Mac
|
|
||||||
##
|
|
||||||
|
|
||||||
|
|
||||||
# globs
|
|
||||||
Makefile.in
|
|
||||||
*.userprefs
|
|
||||||
*.usertasks
|
|
||||||
config.make
|
|
||||||
config.status
|
|
||||||
aclocal.m4
|
|
||||||
install-sh
|
|
||||||
autom4te.cache/
|
|
||||||
*.tar.gz
|
|
||||||
tarballs/
|
|
||||||
test-results/
|
|
||||||
|
|
||||||
# Mac bundle stuff
|
|
||||||
*.dmg
|
|
||||||
*.app
|
|
||||||
|
|
||||||
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
|
|
||||||
# General
|
|
||||||
.DS_Store
|
|
||||||
.AppleDouble
|
|
||||||
.LSOverride
|
|
||||||
|
|
||||||
# Icon must end with two \r
|
|
||||||
Icon
|
|
||||||
|
|
||||||
|
|
||||||
# Thumbnails
|
|
||||||
._*
|
|
||||||
|
|
||||||
# Files that might appear in the root of a volume
|
|
||||||
.DocumentRevisions-V100
|
|
||||||
.fseventsd
|
|
||||||
.Spotlight-V100
|
|
||||||
.TemporaryItems
|
|
||||||
.Trashes
|
|
||||||
.VolumeIcon.icns
|
|
||||||
.com.apple.timemachine.donotpresent
|
|
||||||
|
|
||||||
# Directories potentially created on remote AFP share
|
|
||||||
.AppleDB
|
|
||||||
.AppleDesktop
|
|
||||||
Network Trash Folder
|
|
||||||
Temporary Items
|
|
||||||
.apdisk
|
|
||||||
|
|
||||||
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
|
|
||||||
# Windows thumbnail cache files
|
|
||||||
Thumbs.db
|
|
||||||
ehthumbs.db
|
|
||||||
ehthumbs_vista.db
|
|
||||||
|
|
||||||
# Dump file
|
|
||||||
*.stackdump
|
|
||||||
|
|
||||||
# Folder config file
|
|
||||||
[Dd]esktop.ini
|
|
||||||
|
|
||||||
# Recycle Bin used on file shares
|
|
||||||
$RECYCLE.BIN/
|
|
||||||
|
|
||||||
# Windows Installer files
|
|
||||||
*.cab
|
|
||||||
*.msi
|
|
||||||
*.msix
|
|
||||||
*.msm
|
|
||||||
*.msp
|
|
||||||
|
|
||||||
# Windows shortcuts
|
|
||||||
*.lnk
|
|
||||||
|
|
||||||
# JetBrains Rider
|
|
||||||
.idea/
|
|
||||||
*.sln.iml
|
|
||||||
|
|
||||||
##
|
|
||||||
## Visual Studio Code
|
|
||||||
##
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
|
|
||||||
/DiscordBotWebUI/Data
|
|
||||||
/DiscordBot/Data
|
|
||||||
/WebUI/Data
|
|
||||||
/WebUI_Old/Data
|
|
||||||
/WebUI/bin
|
|
||||||
/WebUI_Old/bin
|
|
||||||
Data/
|
|
||||||
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"rpc.enabled": true,
|
||||||
|
"discord.enabled": true
|
||||||
|
}
|
||||||
BIN
BUILDS/DLL/libopus.dll
Normal file
BIN
BUILDS/DLL/libopus.dll
Normal file
Binary file not shown.
BIN
BUILDS/DLL/libsodium.dll
Normal file
BIN
BUILDS/DLL/libsodium.dll
Normal file
Binary file not shown.
BIN
BUILDS/DLL/opus.dll
Normal file
BIN
BUILDS/DLL/opus.dll
Normal file
Binary file not shown.
268
BUILDS/net5.0/CMD_LevelingSystem.deps.json
Normal file
268
BUILDS/net5.0/CMD_LevelingSystem.deps.json
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v5.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v5.0": {
|
||||||
|
"CMD_LevelingSystem/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"PluginManager": "1.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"CMD_LevelingSystem.dll": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Commands": "3.5.0",
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Interactions": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Discord.Net.Webhook": "3.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Commands.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "13.0.1",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Interactive.Async": "5.0.0",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Core.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Reactive": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Interactions.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Rest.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Webhook.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.WebSocket.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.20.51904"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||||
|
"assemblyVersion": "13.0.0.0",
|
||||||
|
"fileVersion": "13.0.1.25517"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"System.Linq.Async": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Interactive.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Linq.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/System.Reactive.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"PluginManager.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"CMD_LevelingSystem/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-IUtexpvogudb1rllKBWkIEpBVQoToMjtVo81KPkt+gNMe7KtRDcZJgcn6+72viMtyw0e95OJPXFV5VEA/n2OQQ==",
|
||||||
|
"path": "discord.net/3.5.0",
|
||||||
|
"hashPath": "discord.net.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ClTv8aiTlitvS48YatRiTLvgE2f2uKgmHNPVBIuvJBHZO2u4bZCzoN1fid+pZn2sbVOkt8uftlLGzz5DSZlFIA==",
|
||||||
|
"path": "discord.net.commands/3.5.0",
|
||||||
|
"hashPath": "discord.net.commands.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-rCzzaznMVQ+bLMxOpYwTyqm9V22kMy6BxlQisSxemHZDe2Jedz3Clp/a0dToACLz+Dlp3u+jYUfCBnTz7L6f4g==",
|
||||||
|
"path": "discord.net.core/3.5.0",
|
||||||
|
"hashPath": "discord.net.core.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-wE9+V9DJ7r+1s4euOi4sGPIAt4sD7r+Tk5s9mrlbLCHVQTK4KllAvcrL25bPFI38FuFceREEzFoRlTrekSyB2Q==",
|
||||||
|
"path": "discord.net.interactions/3.5.0",
|
||||||
|
"hashPath": "discord.net.interactions.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-BnTdLFuuQsKvCv08VQrD4X1Hw2Xp+MELIRQiDiKfG01IiQlRTN+1gc3LB1zXgn5xBvC0HXjHxwV22GrMD9uKHQ==",
|
||||||
|
"path": "discord.net.rest/3.5.0",
|
||||||
|
"hashPath": "discord.net.rest.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-vCIGZS+m88sQDuFmdbUqg+2RIXS/NJWx8ei3MX+ZEYiAvOkDgQfkIlEnU1NKpds6ivTt5GFlv6UzcWubb5VJ1w==",
|
||||||
|
"path": "discord.net.webhook/3.5.0",
|
||||||
|
"hashPath": "discord.net.webhook.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-LjBOvcP40vJ+dhOtBDi8haEeblPAKpAIqR04NBzTM1/0RVavJZH89ovfSQIk42ygkiOaDV4E2x0Mmh6DRoIYcw==",
|
||||||
|
"path": "discord.net.websocket/3.5.0",
|
||||||
|
"hashPath": "discord.net.websocket.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ORj7Zh81gC69TyvmcUm9tSzytcy8AVousi+IVRAI8nLieQjOFryRusSFh7+aLk16FN9pQNqJAiMd7BTKINK0kA==",
|
||||||
|
"path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0",
|
||||||
|
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||||
|
"path": "newtonsoft.json/13.0.1",
|
||||||
|
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||||
|
"path": "system.collections.immutable/5.0.0",
|
||||||
|
"hashPath": "system.collections.immutable.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-QaqhQVDiULcu4vm6o89+iP329HcK44cETHOYgy/jfEjtzeFy0ZxmuM7nel9ocjnKxEM4yh1mli7hgh8Q9o+/Iw==",
|
||||||
|
"path": "system.interactive.async/5.0.0",
|
||||||
|
"hashPath": "system.interactive.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-cPtIuuH8TIjVHSi2ewwReWGW1PfChPE0LxPIDlfwVcLuTM9GANFTXiMB7k3aC4sk3f0cQU25LNKzx+jZMxijqw==",
|
||||||
|
"path": "system.linq.async/5.0.0",
|
||||||
|
"hashPath": "system.linq.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||||
|
"path": "system.reactive/5.0.0",
|
||||||
|
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==",
|
||||||
|
"path": "system.valuetuple/4.5.0",
|
||||||
|
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BUILDS/net5.0/CMD_LevelingSystem.dll
Normal file
BIN
BUILDS/net5.0/CMD_LevelingSystem.dll
Normal file
Binary file not shown.
268
BUILDS/net5.0/CMD_Utils.deps.json
Normal file
268
BUILDS/net5.0/CMD_Utils.deps.json
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v5.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v5.0": {
|
||||||
|
"CMD_Utils/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"PluginManager": "1.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"CMD_Utils.dll": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Commands": "3.5.0",
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Interactions": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Discord.Net.Webhook": "3.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Commands.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "13.0.1",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Interactive.Async": "5.0.0",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Core.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Reactive": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Interactions.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Rest.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Webhook.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.WebSocket.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.20.51904"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||||
|
"assemblyVersion": "13.0.0.0",
|
||||||
|
"fileVersion": "13.0.1.25517"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"System.Linq.Async": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Interactive.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Linq.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/System.Reactive.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"PluginManager.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"CMD_Utils/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-IUtexpvogudb1rllKBWkIEpBVQoToMjtVo81KPkt+gNMe7KtRDcZJgcn6+72viMtyw0e95OJPXFV5VEA/n2OQQ==",
|
||||||
|
"path": "discord.net/3.5.0",
|
||||||
|
"hashPath": "discord.net.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ClTv8aiTlitvS48YatRiTLvgE2f2uKgmHNPVBIuvJBHZO2u4bZCzoN1fid+pZn2sbVOkt8uftlLGzz5DSZlFIA==",
|
||||||
|
"path": "discord.net.commands/3.5.0",
|
||||||
|
"hashPath": "discord.net.commands.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-rCzzaznMVQ+bLMxOpYwTyqm9V22kMy6BxlQisSxemHZDe2Jedz3Clp/a0dToACLz+Dlp3u+jYUfCBnTz7L6f4g==",
|
||||||
|
"path": "discord.net.core/3.5.0",
|
||||||
|
"hashPath": "discord.net.core.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-wE9+V9DJ7r+1s4euOi4sGPIAt4sD7r+Tk5s9mrlbLCHVQTK4KllAvcrL25bPFI38FuFceREEzFoRlTrekSyB2Q==",
|
||||||
|
"path": "discord.net.interactions/3.5.0",
|
||||||
|
"hashPath": "discord.net.interactions.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-BnTdLFuuQsKvCv08VQrD4X1Hw2Xp+MELIRQiDiKfG01IiQlRTN+1gc3LB1zXgn5xBvC0HXjHxwV22GrMD9uKHQ==",
|
||||||
|
"path": "discord.net.rest/3.5.0",
|
||||||
|
"hashPath": "discord.net.rest.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-vCIGZS+m88sQDuFmdbUqg+2RIXS/NJWx8ei3MX+ZEYiAvOkDgQfkIlEnU1NKpds6ivTt5GFlv6UzcWubb5VJ1w==",
|
||||||
|
"path": "discord.net.webhook/3.5.0",
|
||||||
|
"hashPath": "discord.net.webhook.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-LjBOvcP40vJ+dhOtBDi8haEeblPAKpAIqR04NBzTM1/0RVavJZH89ovfSQIk42ygkiOaDV4E2x0Mmh6DRoIYcw==",
|
||||||
|
"path": "discord.net.websocket/3.5.0",
|
||||||
|
"hashPath": "discord.net.websocket.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ORj7Zh81gC69TyvmcUm9tSzytcy8AVousi+IVRAI8nLieQjOFryRusSFh7+aLk16FN9pQNqJAiMd7BTKINK0kA==",
|
||||||
|
"path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0",
|
||||||
|
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||||
|
"path": "newtonsoft.json/13.0.1",
|
||||||
|
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||||
|
"path": "system.collections.immutable/5.0.0",
|
||||||
|
"hashPath": "system.collections.immutable.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-QaqhQVDiULcu4vm6o89+iP329HcK44cETHOYgy/jfEjtzeFy0ZxmuM7nel9ocjnKxEM4yh1mli7hgh8Q9o+/Iw==",
|
||||||
|
"path": "system.interactive.async/5.0.0",
|
||||||
|
"hashPath": "system.interactive.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-cPtIuuH8TIjVHSi2ewwReWGW1PfChPE0LxPIDlfwVcLuTM9GANFTXiMB7k3aC4sk3f0cQU25LNKzx+jZMxijqw==",
|
||||||
|
"path": "system.linq.async/5.0.0",
|
||||||
|
"hashPath": "system.linq.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||||
|
"path": "system.reactive/5.0.0",
|
||||||
|
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==",
|
||||||
|
"path": "system.valuetuple/4.5.0",
|
||||||
|
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BUILDS/net5.0/CMD_Utils.dll
Normal file
BIN
BUILDS/net5.0/CMD_Utils.dll
Normal file
Binary file not shown.
268
BUILDS/net5.0/EVE_LevelingSystem.deps.json
Normal file
268
BUILDS/net5.0/EVE_LevelingSystem.deps.json
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v5.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v5.0": {
|
||||||
|
"EVE_LevelingSystem/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"PluginManager": "1.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"EVE_LevelingSystem.dll": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Commands": "3.5.0",
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Interactions": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Discord.Net.Webhook": "3.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Commands.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "13.0.1",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Interactive.Async": "5.0.0",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Core.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Reactive": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Interactions.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Rest.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Webhook.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.WebSocket.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.20.51904"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||||
|
"assemblyVersion": "13.0.0.0",
|
||||||
|
"fileVersion": "13.0.1.25517"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"System.Linq.Async": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Interactive.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Linq.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/System.Reactive.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"PluginManager.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"EVE_LevelingSystem/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-IUtexpvogudb1rllKBWkIEpBVQoToMjtVo81KPkt+gNMe7KtRDcZJgcn6+72viMtyw0e95OJPXFV5VEA/n2OQQ==",
|
||||||
|
"path": "discord.net/3.5.0",
|
||||||
|
"hashPath": "discord.net.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ClTv8aiTlitvS48YatRiTLvgE2f2uKgmHNPVBIuvJBHZO2u4bZCzoN1fid+pZn2sbVOkt8uftlLGzz5DSZlFIA==",
|
||||||
|
"path": "discord.net.commands/3.5.0",
|
||||||
|
"hashPath": "discord.net.commands.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-rCzzaznMVQ+bLMxOpYwTyqm9V22kMy6BxlQisSxemHZDe2Jedz3Clp/a0dToACLz+Dlp3u+jYUfCBnTz7L6f4g==",
|
||||||
|
"path": "discord.net.core/3.5.0",
|
||||||
|
"hashPath": "discord.net.core.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-wE9+V9DJ7r+1s4euOi4sGPIAt4sD7r+Tk5s9mrlbLCHVQTK4KllAvcrL25bPFI38FuFceREEzFoRlTrekSyB2Q==",
|
||||||
|
"path": "discord.net.interactions/3.5.0",
|
||||||
|
"hashPath": "discord.net.interactions.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-BnTdLFuuQsKvCv08VQrD4X1Hw2Xp+MELIRQiDiKfG01IiQlRTN+1gc3LB1zXgn5xBvC0HXjHxwV22GrMD9uKHQ==",
|
||||||
|
"path": "discord.net.rest/3.5.0",
|
||||||
|
"hashPath": "discord.net.rest.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-vCIGZS+m88sQDuFmdbUqg+2RIXS/NJWx8ei3MX+ZEYiAvOkDgQfkIlEnU1NKpds6ivTt5GFlv6UzcWubb5VJ1w==",
|
||||||
|
"path": "discord.net.webhook/3.5.0",
|
||||||
|
"hashPath": "discord.net.webhook.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-LjBOvcP40vJ+dhOtBDi8haEeblPAKpAIqR04NBzTM1/0RVavJZH89ovfSQIk42ygkiOaDV4E2x0Mmh6DRoIYcw==",
|
||||||
|
"path": "discord.net.websocket/3.5.0",
|
||||||
|
"hashPath": "discord.net.websocket.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ORj7Zh81gC69TyvmcUm9tSzytcy8AVousi+IVRAI8nLieQjOFryRusSFh7+aLk16FN9pQNqJAiMd7BTKINK0kA==",
|
||||||
|
"path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0",
|
||||||
|
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||||
|
"path": "newtonsoft.json/13.0.1",
|
||||||
|
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||||
|
"path": "system.collections.immutable/5.0.0",
|
||||||
|
"hashPath": "system.collections.immutable.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-QaqhQVDiULcu4vm6o89+iP329HcK44cETHOYgy/jfEjtzeFy0ZxmuM7nel9ocjnKxEM4yh1mli7hgh8Q9o+/Iw==",
|
||||||
|
"path": "system.interactive.async/5.0.0",
|
||||||
|
"hashPath": "system.interactive.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-cPtIuuH8TIjVHSi2ewwReWGW1PfChPE0LxPIDlfwVcLuTM9GANFTXiMB7k3aC4sk3f0cQU25LNKzx+jZMxijqw==",
|
||||||
|
"path": "system.linq.async/5.0.0",
|
||||||
|
"hashPath": "system.linq.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||||
|
"path": "system.reactive/5.0.0",
|
||||||
|
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==",
|
||||||
|
"path": "system.valuetuple/4.5.0",
|
||||||
|
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BUILDS/net5.0/EVE_LevelingSystem.dll
Normal file
BIN
BUILDS/net5.0/EVE_LevelingSystem.dll
Normal file
Binary file not shown.
268
BUILDS/net5.0/MusicCommands.deps.json
Normal file
268
BUILDS/net5.0/MusicCommands.deps.json
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v5.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v5.0": {
|
||||||
|
"MusicCommands/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"PluginManager": "1.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"MusicCommands.dll": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Commands": "3.5.0",
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Interactions": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Discord.Net.Webhook": "3.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Commands.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "13.0.1",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Interactive.Async": "5.0.0",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Core.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Reactive": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Interactions.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Rest.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Webhook.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.WebSocket.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.20.51904"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||||
|
"assemblyVersion": "13.0.0.0",
|
||||||
|
"fileVersion": "13.0.1.25517"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"System.Linq.Async": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Interactive.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Linq.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/System.Reactive.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"PluginManager.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"MusicCommands/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-IUtexpvogudb1rllKBWkIEpBVQoToMjtVo81KPkt+gNMe7KtRDcZJgcn6+72viMtyw0e95OJPXFV5VEA/n2OQQ==",
|
||||||
|
"path": "discord.net/3.5.0",
|
||||||
|
"hashPath": "discord.net.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ClTv8aiTlitvS48YatRiTLvgE2f2uKgmHNPVBIuvJBHZO2u4bZCzoN1fid+pZn2sbVOkt8uftlLGzz5DSZlFIA==",
|
||||||
|
"path": "discord.net.commands/3.5.0",
|
||||||
|
"hashPath": "discord.net.commands.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-rCzzaznMVQ+bLMxOpYwTyqm9V22kMy6BxlQisSxemHZDe2Jedz3Clp/a0dToACLz+Dlp3u+jYUfCBnTz7L6f4g==",
|
||||||
|
"path": "discord.net.core/3.5.0",
|
||||||
|
"hashPath": "discord.net.core.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-wE9+V9DJ7r+1s4euOi4sGPIAt4sD7r+Tk5s9mrlbLCHVQTK4KllAvcrL25bPFI38FuFceREEzFoRlTrekSyB2Q==",
|
||||||
|
"path": "discord.net.interactions/3.5.0",
|
||||||
|
"hashPath": "discord.net.interactions.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-BnTdLFuuQsKvCv08VQrD4X1Hw2Xp+MELIRQiDiKfG01IiQlRTN+1gc3LB1zXgn5xBvC0HXjHxwV22GrMD9uKHQ==",
|
||||||
|
"path": "discord.net.rest/3.5.0",
|
||||||
|
"hashPath": "discord.net.rest.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-vCIGZS+m88sQDuFmdbUqg+2RIXS/NJWx8ei3MX+ZEYiAvOkDgQfkIlEnU1NKpds6ivTt5GFlv6UzcWubb5VJ1w==",
|
||||||
|
"path": "discord.net.webhook/3.5.0",
|
||||||
|
"hashPath": "discord.net.webhook.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-LjBOvcP40vJ+dhOtBDi8haEeblPAKpAIqR04NBzTM1/0RVavJZH89ovfSQIk42ygkiOaDV4E2x0Mmh6DRoIYcw==",
|
||||||
|
"path": "discord.net.websocket/3.5.0",
|
||||||
|
"hashPath": "discord.net.websocket.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ORj7Zh81gC69TyvmcUm9tSzytcy8AVousi+IVRAI8nLieQjOFryRusSFh7+aLk16FN9pQNqJAiMd7BTKINK0kA==",
|
||||||
|
"path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0",
|
||||||
|
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||||
|
"path": "newtonsoft.json/13.0.1",
|
||||||
|
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||||
|
"path": "system.collections.immutable/5.0.0",
|
||||||
|
"hashPath": "system.collections.immutable.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-QaqhQVDiULcu4vm6o89+iP329HcK44cETHOYgy/jfEjtzeFy0ZxmuM7nel9ocjnKxEM4yh1mli7hgh8Q9o+/Iw==",
|
||||||
|
"path": "system.interactive.async/5.0.0",
|
||||||
|
"hashPath": "system.interactive.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-cPtIuuH8TIjVHSi2ewwReWGW1PfChPE0LxPIDlfwVcLuTM9GANFTXiMB7k3aC4sk3f0cQU25LNKzx+jZMxijqw==",
|
||||||
|
"path": "system.linq.async/5.0.0",
|
||||||
|
"hashPath": "system.linq.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||||
|
"path": "system.reactive/5.0.0",
|
||||||
|
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==",
|
||||||
|
"path": "system.valuetuple/4.5.0",
|
||||||
|
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BUILDS/net5.0/MusicCommands.dll
Normal file
BIN
BUILDS/net5.0/MusicCommands.dll
Normal file
Binary file not shown.
BIN
BUILDS/net5.0/PluginManager.dll
Normal file
BIN
BUILDS/net5.0/PluginManager.dll
Normal file
Binary file not shown.
268
BUILDS/net5.0/StartupEvents.deps.json
Normal file
268
BUILDS/net5.0/StartupEvents.deps.json
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v5.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v5.0": {
|
||||||
|
"StartupEvents/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"PluginManager": "1.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"StartupEvents.dll": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Commands": "3.5.0",
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Interactions": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Discord.Net.Webhook": "3.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Commands.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "13.0.1",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Interactive.Async": "5.0.0",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Core.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0",
|
||||||
|
"Discord.Net.WebSocket": "3.5.0",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Reactive": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Interactions.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Rest.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.Webhook.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.5.0",
|
||||||
|
"Discord.Net.Rest": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/Discord.Net.WebSocket.dll": {
|
||||||
|
"assemblyVersion": "3.5.0.0",
|
||||||
|
"fileVersion": "3.5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.20.51904"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||||
|
"assemblyVersion": "13.0.0.0",
|
||||||
|
"fileVersion": "13.0.1.25517"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"System.Linq.Async": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Interactive.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Linq.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/System.Reactive.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net": "3.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"PluginManager.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"StartupEvents/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
},
|
||||||
|
"Discord.Net/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-IUtexpvogudb1rllKBWkIEpBVQoToMjtVo81KPkt+gNMe7KtRDcZJgcn6+72viMtyw0e95OJPXFV5VEA/n2OQQ==",
|
||||||
|
"path": "discord.net/3.5.0",
|
||||||
|
"hashPath": "discord.net.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ClTv8aiTlitvS48YatRiTLvgE2f2uKgmHNPVBIuvJBHZO2u4bZCzoN1fid+pZn2sbVOkt8uftlLGzz5DSZlFIA==",
|
||||||
|
"path": "discord.net.commands/3.5.0",
|
||||||
|
"hashPath": "discord.net.commands.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-rCzzaznMVQ+bLMxOpYwTyqm9V22kMy6BxlQisSxemHZDe2Jedz3Clp/a0dToACLz+Dlp3u+jYUfCBnTz7L6f4g==",
|
||||||
|
"path": "discord.net.core/3.5.0",
|
||||||
|
"hashPath": "discord.net.core.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-wE9+V9DJ7r+1s4euOi4sGPIAt4sD7r+Tk5s9mrlbLCHVQTK4KllAvcrL25bPFI38FuFceREEzFoRlTrekSyB2Q==",
|
||||||
|
"path": "discord.net.interactions/3.5.0",
|
||||||
|
"hashPath": "discord.net.interactions.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-BnTdLFuuQsKvCv08VQrD4X1Hw2Xp+MELIRQiDiKfG01IiQlRTN+1gc3LB1zXgn5xBvC0HXjHxwV22GrMD9uKHQ==",
|
||||||
|
"path": "discord.net.rest/3.5.0",
|
||||||
|
"hashPath": "discord.net.rest.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-vCIGZS+m88sQDuFmdbUqg+2RIXS/NJWx8ei3MX+ZEYiAvOkDgQfkIlEnU1NKpds6ivTt5GFlv6UzcWubb5VJ1w==",
|
||||||
|
"path": "discord.net.webhook/3.5.0",
|
||||||
|
"hashPath": "discord.net.webhook.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-LjBOvcP40vJ+dhOtBDi8haEeblPAKpAIqR04NBzTM1/0RVavJZH89ovfSQIk42ygkiOaDV4E2x0Mmh6DRoIYcw==",
|
||||||
|
"path": "discord.net.websocket/3.5.0",
|
||||||
|
"hashPath": "discord.net.websocket.3.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ORj7Zh81gC69TyvmcUm9tSzytcy8AVousi+IVRAI8nLieQjOFryRusSFh7+aLk16FN9pQNqJAiMd7BTKINK0kA==",
|
||||||
|
"path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0",
|
||||||
|
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||||
|
"path": "newtonsoft.json/13.0.1",
|
||||||
|
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||||
|
"path": "system.collections.immutable/5.0.0",
|
||||||
|
"hashPath": "system.collections.immutable.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-QaqhQVDiULcu4vm6o89+iP329HcK44cETHOYgy/jfEjtzeFy0ZxmuM7nel9ocjnKxEM4yh1mli7hgh8Q9o+/Iw==",
|
||||||
|
"path": "system.interactive.async/5.0.0",
|
||||||
|
"hashPath": "system.interactive.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-cPtIuuH8TIjVHSi2ewwReWGW1PfChPE0LxPIDlfwVcLuTM9GANFTXiMB7k3aC4sk3f0cQU25LNKzx+jZMxijqw==",
|
||||||
|
"path": "system.linq.async/5.0.0",
|
||||||
|
"hashPath": "system.linq.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||||
|
"path": "system.reactive/5.0.0",
|
||||||
|
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==",
|
||||||
|
"path": "system.valuetuple/4.5.0",
|
||||||
|
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BUILDS/net5.0/StartupEvents.dll
Normal file
BIN
BUILDS/net5.0/StartupEvents.dll
Normal file
Binary file not shown.
BIN
BUILDS/net5.0/ref/CMD_LevelingSystem.dll
Normal file
BIN
BUILDS/net5.0/ref/CMD_LevelingSystem.dll
Normal file
Binary file not shown.
BIN
BUILDS/net5.0/ref/CMD_Utils.dll
Normal file
BIN
BUILDS/net5.0/ref/CMD_Utils.dll
Normal file
Binary file not shown.
BIN
BUILDS/net5.0/ref/EVE_LevelingSystem.dll
Normal file
BIN
BUILDS/net5.0/ref/EVE_LevelingSystem.dll
Normal file
Binary file not shown.
BIN
BUILDS/net5.0/ref/MusicCommands.dll
Normal file
BIN
BUILDS/net5.0/ref/MusicCommands.dll
Normal file
Binary file not shown.
BIN
BUILDS/net5.0/ref/StartupEvents.dll
Normal file
BIN
BUILDS/net5.0/ref/StartupEvents.dll
Normal file
Binary file not shown.
268
BUILDS/net6.0/CMD_Utils.deps.json
Normal file
268
BUILDS/net6.0/CMD_Utils.deps.json
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v6.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v6.0": {
|
||||||
|
"CMD_Utils/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"PluginManager": "1.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"CMD_Utils.dll": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Commands": "3.7.2",
|
||||||
|
"Discord.Net.Core": "3.7.2",
|
||||||
|
"Discord.Net.Interactions": "3.7.2",
|
||||||
|
"Discord.Net.Rest": "3.7.2",
|
||||||
|
"Discord.Net.WebSocket": "3.7.2",
|
||||||
|
"Discord.Net.Webhook": "3.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Commands.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "13.0.1",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Interactive.Async": "5.0.0",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Core.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2",
|
||||||
|
"Discord.Net.Rest": "3.7.2",
|
||||||
|
"Discord.Net.WebSocket": "3.7.2",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Reactive": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Interactions.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Rest.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2",
|
||||||
|
"Discord.Net.Rest": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Webhook.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2",
|
||||||
|
"Discord.Net.Rest": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.WebSocket.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.20.51904"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||||
|
"assemblyVersion": "13.0.0.0",
|
||||||
|
"fileVersion": "13.0.1.25517"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"System.Linq.Async": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Interactive.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Linq.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/System.Reactive.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"PluginManager.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"CMD_Utils/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
},
|
||||||
|
"Discord.Net/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-FAiCLGu5rp6+Z10FjKbbJ6LLpKjbMBGpozixkJlz5LZvuncPx8f4AWFAw7pBecKUuAh983qiZ8CZYZcNXsI4qg==",
|
||||||
|
"path": "discord.net/3.7.2",
|
||||||
|
"hashPath": "discord.net.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-aOEGP04X64htsTr7ozKj9qHpmvOfitSw5gfR8Tw9TX0+FdswD2LNL2KfOAIaxRKZmRTm34aXQEJrVq0K8AptmQ==",
|
||||||
|
"path": "discord.net.commands/3.7.2",
|
||||||
|
"hashPath": "discord.net.commands.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-apwswc6LjN4dj3u27SO3Hr56Jzl91wzReahieoD7IQhV+BJQaRxhTRiEEWFTrBzHfeFHEOQ7r6vZnra3zeFhKA==",
|
||||||
|
"path": "discord.net.core/3.7.2",
|
||||||
|
"hashPath": "discord.net.core.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-dwGhEdDB0yyo/lGtjwIDVZmsuD52di7lIZWu/sBtvvA05dMgYZq5S6ILdsBXjOyaHeXd+EV4YMlj2VS/rm619w==",
|
||||||
|
"path": "discord.net.interactions/3.7.2",
|
||||||
|
"hashPath": "discord.net.interactions.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-dyp8YaMBNJ837EH1KNz2PNGZqc2y71WFd1+pdldF+pLQJ3Gf/+V7685paAR7bQw7yFNyqEBR/QRBCNp+QIQ7Wg==",
|
||||||
|
"path": "discord.net.rest/3.7.2",
|
||||||
|
"hashPath": "discord.net.rest.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-da3i/mTq2y7mfj3xlHH14S4PivHbflJCVr8OUikJtQrxBOxvPkqP7ZYk3Y9S28q0K8qik+TUjCcjL5gELKrh/A==",
|
||||||
|
"path": "discord.net.webhook/3.7.2",
|
||||||
|
"hashPath": "discord.net.webhook.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-pYCd6ET44ADaNiyEw82TaJnR7TKYHfrKCytWFWMPL5faJhoh260avZn3Hwunlf331lEQ0f4K1CujPkQbNuq7kQ==",
|
||||||
|
"path": "discord.net.websocket/3.7.2",
|
||||||
|
"hashPath": "discord.net.websocket.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ORj7Zh81gC69TyvmcUm9tSzytcy8AVousi+IVRAI8nLieQjOFryRusSFh7+aLk16FN9pQNqJAiMd7BTKINK0kA==",
|
||||||
|
"path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0",
|
||||||
|
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||||
|
"path": "newtonsoft.json/13.0.1",
|
||||||
|
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||||
|
"path": "system.collections.immutable/5.0.0",
|
||||||
|
"hashPath": "system.collections.immutable.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-QaqhQVDiULcu4vm6o89+iP329HcK44cETHOYgy/jfEjtzeFy0ZxmuM7nel9ocjnKxEM4yh1mli7hgh8Q9o+/Iw==",
|
||||||
|
"path": "system.interactive.async/5.0.0",
|
||||||
|
"hashPath": "system.interactive.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-cPtIuuH8TIjVHSi2ewwReWGW1PfChPE0LxPIDlfwVcLuTM9GANFTXiMB7k3aC4sk3f0cQU25LNKzx+jZMxijqw==",
|
||||||
|
"path": "system.linq.async/5.0.0",
|
||||||
|
"hashPath": "system.linq.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||||
|
"path": "system.reactive/5.0.0",
|
||||||
|
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==",
|
||||||
|
"path": "system.valuetuple/4.5.0",
|
||||||
|
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BUILDS/net6.0/CMD_Utils.dll
Normal file
BIN
BUILDS/net6.0/CMD_Utils.dll
Normal file
Binary file not shown.
268
BUILDS/net6.0/MusicCommands.deps.json
Normal file
268
BUILDS/net6.0/MusicCommands.deps.json
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v6.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v6.0": {
|
||||||
|
"MusicCommands/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"PluginManager": "1.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"MusicCommands.dll": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Commands": "3.7.2",
|
||||||
|
"Discord.Net.Core": "3.7.2",
|
||||||
|
"Discord.Net.Interactions": "3.7.2",
|
||||||
|
"Discord.Net.Rest": "3.7.2",
|
||||||
|
"Discord.Net.WebSocket": "3.7.2",
|
||||||
|
"Discord.Net.Webhook": "3.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Commands.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "13.0.1",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Interactive.Async": "5.0.0",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Core.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2",
|
||||||
|
"Discord.Net.Rest": "3.7.2",
|
||||||
|
"Discord.Net.WebSocket": "3.7.2",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0",
|
||||||
|
"System.Collections.Immutable": "5.0.0",
|
||||||
|
"System.Reactive": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Interactions.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Rest.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2",
|
||||||
|
"Discord.Net.Rest": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.Webhook.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.7.2": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net.Core": "3.7.2",
|
||||||
|
"Discord.Net.Rest": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Discord.Net.WebSocket.dll": {
|
||||||
|
"assemblyVersion": "3.7.2.0",
|
||||||
|
"fileVersion": "3.7.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.20.51904"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||||
|
"assemblyVersion": "13.0.0.0",
|
||||||
|
"fileVersion": "13.0.1.25517"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"System.Linq.Async": "5.0.0"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Interactive.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/netcoreapp3.1/System.Linq.Async.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net5.0/System.Reactive.dll": {
|
||||||
|
"assemblyVersion": "5.0.0.0",
|
||||||
|
"fileVersion": "5.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Discord.Net": "3.7.2"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"PluginManager.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"MusicCommands/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
},
|
||||||
|
"Discord.Net/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-FAiCLGu5rp6+Z10FjKbbJ6LLpKjbMBGpozixkJlz5LZvuncPx8f4AWFAw7pBecKUuAh983qiZ8CZYZcNXsI4qg==",
|
||||||
|
"path": "discord.net/3.7.2",
|
||||||
|
"hashPath": "discord.net.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Commands/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-aOEGP04X64htsTr7ozKj9qHpmvOfitSw5gfR8Tw9TX0+FdswD2LNL2KfOAIaxRKZmRTm34aXQEJrVq0K8AptmQ==",
|
||||||
|
"path": "discord.net.commands/3.7.2",
|
||||||
|
"hashPath": "discord.net.commands.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Core/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-apwswc6LjN4dj3u27SO3Hr56Jzl91wzReahieoD7IQhV+BJQaRxhTRiEEWFTrBzHfeFHEOQ7r6vZnra3zeFhKA==",
|
||||||
|
"path": "discord.net.core/3.7.2",
|
||||||
|
"hashPath": "discord.net.core.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Interactions/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-dwGhEdDB0yyo/lGtjwIDVZmsuD52di7lIZWu/sBtvvA05dMgYZq5S6ILdsBXjOyaHeXd+EV4YMlj2VS/rm619w==",
|
||||||
|
"path": "discord.net.interactions/3.7.2",
|
||||||
|
"hashPath": "discord.net.interactions.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Rest/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-dyp8YaMBNJ837EH1KNz2PNGZqc2y71WFd1+pdldF+pLQJ3Gf/+V7685paAR7bQw7yFNyqEBR/QRBCNp+QIQ7Wg==",
|
||||||
|
"path": "discord.net.rest/3.7.2",
|
||||||
|
"hashPath": "discord.net.rest.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.Webhook/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-da3i/mTq2y7mfj3xlHH14S4PivHbflJCVr8OUikJtQrxBOxvPkqP7ZYk3Y9S28q0K8qik+TUjCcjL5gELKrh/A==",
|
||||||
|
"path": "discord.net.webhook/3.7.2",
|
||||||
|
"hashPath": "discord.net.webhook.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Discord.Net.WebSocket/3.7.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-pYCd6ET44ADaNiyEw82TaJnR7TKYHfrKCytWFWMPL5faJhoh260avZn3Hwunlf331lEQ0f4K1CujPkQbNuq7kQ==",
|
||||||
|
"path": "discord.net.websocket/3.7.2",
|
||||||
|
"hashPath": "discord.net.websocket.3.7.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ORj7Zh81gC69TyvmcUm9tSzytcy8AVousi+IVRAI8nLieQjOFryRusSFh7+aLk16FN9pQNqJAiMd7BTKINK0kA==",
|
||||||
|
"path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0",
|
||||||
|
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.1": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||||
|
"path": "newtonsoft.json/13.0.1",
|
||||||
|
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||||
|
"path": "system.collections.immutable/5.0.0",
|
||||||
|
"hashPath": "system.collections.immutable.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Interactive.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-QaqhQVDiULcu4vm6o89+iP329HcK44cETHOYgy/jfEjtzeFy0ZxmuM7nel9ocjnKxEM4yh1mli7hgh8Q9o+/Iw==",
|
||||||
|
"path": "system.interactive.async/5.0.0",
|
||||||
|
"hashPath": "system.interactive.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Linq.Async/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-cPtIuuH8TIjVHSi2ewwReWGW1PfChPE0LxPIDlfwVcLuTM9GANFTXiMB7k3aC4sk3f0cQU25LNKzx+jZMxijqw==",
|
||||||
|
"path": "system.linq.async/5.0.0",
|
||||||
|
"hashPath": "system.linq.async.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Reactive/5.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||||
|
"path": "system.reactive/5.0.0",
|
||||||
|
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.ValueTuple/4.5.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==",
|
||||||
|
"path": "system.valuetuple/4.5.0",
|
||||||
|
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"PluginManager/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BUILDS/net6.0/MusicCommands.dll
Normal file
BIN
BUILDS/net6.0/MusicCommands.dll
Normal file
Binary file not shown.
BIN
BUILDS/net6.0/PluginManager.dll
Normal file
BIN
BUILDS/net6.0/PluginManager.dll
Normal file
Binary file not shown.
BIN
BUILDS/net6.0/Plugins/Commands/CMD_LevelingSystem.dll
Normal file
BIN
BUILDS/net6.0/Plugins/Commands/CMD_LevelingSystem.dll
Normal file
Binary file not shown.
BIN
BUILDS/net6.0/Plugins/Commands/CMD_Utils.dll
Normal file
BIN
BUILDS/net6.0/Plugins/Commands/CMD_Utils.dll
Normal file
Binary file not shown.
BIN
BUILDS/net6.0/Plugins/Commands/MusicCommands.dll
Normal file
BIN
BUILDS/net6.0/Plugins/Commands/MusicCommands.dll
Normal file
Binary file not shown.
BIN
BUILDS/net6.0/Plugins/Events/EVE_LevelingSystem.dll
Normal file
BIN
BUILDS/net6.0/Plugins/Events/EVE_LevelingSystem.dll
Normal file
Binary file not shown.
14
CMD_LevelingSystem/CMD_LevelingSystem.csproj
Normal file
14
CMD_LevelingSystem/CMD_LevelingSystem.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<BaseOutputPath>..\DiscordBot\bin\Debug\net6.0\Data\Plugins\Commands\LevelingSystem</BaseOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\PluginManager\PluginManager.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
48
CMD_LevelingSystem/Level.cs
Normal file
48
CMD_LevelingSystem/Level.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace CMD_LevelingSystem;
|
||||||
|
|
||||||
|
internal class Level : DBCommand
|
||||||
|
{
|
||||||
|
public string Command => "level";
|
||||||
|
|
||||||
|
public string Description => "Display tour current level";
|
||||||
|
|
||||||
|
public string Usage => "level";
|
||||||
|
|
||||||
|
public bool canUseDM => false;
|
||||||
|
|
||||||
|
public bool canUseServer => true;
|
||||||
|
|
||||||
|
public bool requireAdmin => false;
|
||||||
|
|
||||||
|
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
|
||||||
|
{
|
||||||
|
if (!File.Exists(Config.GetValue<string>("LevelingSystemPath") + $"/{message.Author.Id}.dat"))
|
||||||
|
{
|
||||||
|
await context.Channel.SendMessageAsync("You are now unranked !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await Functions.ConvertFromJson<User>(Config.GetValue<string>("LevelingSystemPath") + $"/{message.Author.Id}.dat");
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
await context.Channel.SendMessageAsync("You are now unranked !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new EmbedBuilder();
|
||||||
|
var r = new Random();
|
||||||
|
builder.WithColor(r.Next(256), r.Next(256), r.Next(256));
|
||||||
|
builder.AddField("Current Level", user.CurrentLevel, true)
|
||||||
|
.AddField("Current EXP", user.CurrentEXP, true)
|
||||||
|
.AddField("Required Exp", user.RequiredEXPToLevelUp, true);
|
||||||
|
builder.WithTimestamp(DateTimeOffset.Now);
|
||||||
|
await context.Channel.SendMessageAsync(embed: builder.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
18
CMD_LevelingSystem/User.cs
Normal file
18
CMD_LevelingSystem/User.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
|
namespace CMD_LevelingSystem;
|
||||||
|
|
||||||
|
public class DiscordUser
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public ushort DiscordTag { get; set; }
|
||||||
|
public ulong userID { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
public DiscordUser user { get; set; }
|
||||||
|
public int CurrentLevel { get; set; }
|
||||||
|
public long CurrentEXP { get; set; }
|
||||||
|
public long RequiredEXPToLevelUp { get; set; }
|
||||||
|
}
|
||||||
19
CMD_Utils/CMD_Utils.csproj
Normal file
19
CMD_Utils/CMD_Utils.csproj
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<BaseOutputPath></BaseOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<OutputPath>..\BUILDS\</OutputPath>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
<DebugSymbols>false</DebugSymbols>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\PluginManager\PluginManager.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
23
CMD_Utils/Echo.cs
Normal file
23
CMD_Utils/Echo.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
|
||||||
|
internal class Echo : DBCommand
|
||||||
|
{
|
||||||
|
public string Command => "echo";
|
||||||
|
|
||||||
|
public string Description => "Replay with the same message";
|
||||||
|
|
||||||
|
public string Usage => "echo [message]";
|
||||||
|
|
||||||
|
public bool canUseDM => true;
|
||||||
|
public bool canUseServer => true;
|
||||||
|
|
||||||
|
public bool requireAdmin => false;
|
||||||
|
|
||||||
|
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
|
||||||
|
{
|
||||||
|
var m = message.Content.Substring(6);
|
||||||
|
await message.Channel.SendMessageAsync(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
CMD_Utils/FlipCoin.cs
Normal file
30
CMD_Utils/FlipCoin.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
|
||||||
|
namespace CMD_Utils;
|
||||||
|
|
||||||
|
internal class FlipCoin : DBCommand
|
||||||
|
{
|
||||||
|
public string Command => "flip";
|
||||||
|
|
||||||
|
public string Description => "Flip a coin";
|
||||||
|
|
||||||
|
public string Usage => "flip";
|
||||||
|
|
||||||
|
public bool canUseDM => true;
|
||||||
|
|
||||||
|
public bool canUseServer => true;
|
||||||
|
|
||||||
|
public bool requireAdmin => false;
|
||||||
|
|
||||||
|
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
|
||||||
|
{
|
||||||
|
var random = new System.Random();
|
||||||
|
var r = random.Next(1, 3);
|
||||||
|
if (r == 1)
|
||||||
|
await message.Channel.SendMessageAsync("Heads");
|
||||||
|
else
|
||||||
|
await message.Channel.SendMessageAsync("Tails");
|
||||||
|
}
|
||||||
|
}
|
||||||
45
CMD_Utils/Poll.cs
Normal file
45
CMD_Utils/Poll.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace CMD_Utils;
|
||||||
|
|
||||||
|
public class Poll : DBCommand
|
||||||
|
{
|
||||||
|
public string Command => "poll";
|
||||||
|
|
||||||
|
public string Description => "Create a poll with options";
|
||||||
|
|
||||||
|
public string Usage => "poll [This-is-question] [This-is-answer-1] [This-is-answer-2] ... ";
|
||||||
|
|
||||||
|
public bool canUseDM => false;
|
||||||
|
|
||||||
|
public bool canUseServer => true;
|
||||||
|
|
||||||
|
public bool requireAdmin => true;
|
||||||
|
|
||||||
|
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
|
||||||
|
{
|
||||||
|
if (isDM) return;
|
||||||
|
var question = message.Content.Split(' ')[1].Replace('-', ' ');
|
||||||
|
var answers = Functions.MergeStrings(message.Content.Split(' '), 2).Split(' ');
|
||||||
|
var embedBuilder = new EmbedBuilder();
|
||||||
|
embedBuilder.Title = question;
|
||||||
|
var len = answers.Length;
|
||||||
|
for (var i = 0; i < len; i++) embedBuilder.AddField($"Answer {i + 1}", answers[i].Replace('-', ' '), true);
|
||||||
|
var msg = await context.Channel.SendMessageAsync(embed: embedBuilder.Build());
|
||||||
|
|
||||||
|
var emotes = new List<IEmote>();
|
||||||
|
emotes.Add(Emoji.Parse(":one:"));
|
||||||
|
emotes.Add(Emoji.Parse(":two:"));
|
||||||
|
emotes.Add(Emoji.Parse(":three:"));
|
||||||
|
emotes.Add(Emoji.Parse(":four:"));
|
||||||
|
emotes.Add(Emoji.Parse(":five:"));
|
||||||
|
emotes.Add(Emoji.Parse(":six:"));
|
||||||
|
|
||||||
|
for (var i = 0; i < len; i++) await msg.AddReactionAsync(emotes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
CMD_Utils/Random.cs
Normal file
39
CMD_Utils/Random.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
|
||||||
|
public class Random : DBCommand
|
||||||
|
{
|
||||||
|
public string Command => "random";
|
||||||
|
|
||||||
|
public string Description => "random number between number1 and number2";
|
||||||
|
|
||||||
|
public string Usage => "random [number1] [number2]";
|
||||||
|
|
||||||
|
public bool canUseDM => true;
|
||||||
|
public bool canUseServer => true;
|
||||||
|
public bool requireAdmin => false;
|
||||||
|
|
||||||
|
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var msg = message.Content;
|
||||||
|
var a = int.Parse(msg.Split(' ')[1]);
|
||||||
|
var b = int.Parse(msg.Split(' ')[2]);
|
||||||
|
|
||||||
|
if (a > b)
|
||||||
|
{
|
||||||
|
var temp = a;
|
||||||
|
a = b;
|
||||||
|
b = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
await message.Channel.SendMessageAsync("Your random generated number is " + new System.Random().Next(a, b));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await message.Channel.SendMessageAsync("Invalid numbers or no numbers:\nUsage: " + Usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
DiscordBot.dll
Normal file
BIN
DiscordBot.dll
Normal file
Binary file not shown.
4
DiscordBot/App.config
Normal file
4
DiscordBot/App.config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="4.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
100
DiscordBot/Discord/Commands/Help.cs
Normal file
100
DiscordBot/Discord/Commands/Help.cs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Loaders;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace DiscordBot.Discord.Commands;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The help command
|
||||||
|
/// </summary>
|
||||||
|
internal class Help : DBCommand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Command name
|
||||||
|
/// </summary>
|
||||||
|
public string Command => "help";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command Description
|
||||||
|
/// </summary>
|
||||||
|
public string Description => "This command allows you to check all loadded commands";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command usage
|
||||||
|
/// </summary>
|
||||||
|
public string Usage => "help";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the command can be used <inheritdoca DM <see cref="IChannel" />/>
|
||||||
|
/// </summary>
|
||||||
|
public bool canUseDM => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the command can be used in a server
|
||||||
|
/// </summary>
|
||||||
|
public bool canUseServer => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the command require administrator to be executed
|
||||||
|
/// </summary>
|
||||||
|
public bool requireAdmin => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The main body of the command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The command context</param>
|
||||||
|
/// <param name="message">The command message</param>
|
||||||
|
/// <param name="client">The discord bot client</param>
|
||||||
|
/// <param name="isDM">True if the message was sent from a DM channel, false otherwise</param>
|
||||||
|
public void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
|
||||||
|
{
|
||||||
|
var args = Functions.GetArguments(message);
|
||||||
|
if (args.Count != 0)
|
||||||
|
{
|
||||||
|
foreach (var item in args)
|
||||||
|
{
|
||||||
|
var e = GenerateHelpCommand(item);
|
||||||
|
if (e != null)
|
||||||
|
context.Channel.SendMessageAsync(embed: e.Build());
|
||||||
|
else
|
||||||
|
context.Channel.SendMessageAsync("Unknown Command " + item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var embedBuilder = new EmbedBuilder();
|
||||||
|
|
||||||
|
var adminCommands = "";
|
||||||
|
var normalCommands = "";
|
||||||
|
var DMCommands = "";
|
||||||
|
|
||||||
|
foreach (var cmd in PluginLoader.Commands!)
|
||||||
|
{
|
||||||
|
if (cmd.canUseDM) DMCommands += cmd.Command + " ";
|
||||||
|
if (cmd.requireAdmin)
|
||||||
|
adminCommands += cmd.Command + " ";
|
||||||
|
else if (cmd.canUseServer) normalCommands += cmd.Command + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
embedBuilder.AddField("Admin Commands", adminCommands);
|
||||||
|
embedBuilder.AddField("Normal Commands", normalCommands);
|
||||||
|
embedBuilder.AddField("DM Commands", DMCommands);
|
||||||
|
context.Channel.SendMessageAsync(embed: embedBuilder.Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmbedBuilder GenerateHelpCommand(string command)
|
||||||
|
{
|
||||||
|
var embedBuilder = new EmbedBuilder();
|
||||||
|
var cmd = PluginLoader.Commands.Find(p => p.Command == command);
|
||||||
|
if (cmd == null) return null;
|
||||||
|
|
||||||
|
embedBuilder.AddField("Usage", cmd.Usage);
|
||||||
|
embedBuilder.AddField("Description", cmd.Description);
|
||||||
|
|
||||||
|
return embedBuilder;
|
||||||
|
}
|
||||||
|
}
|
||||||
113
DiscordBot/Discord/Commands/Restart.cs
Normal file
113
DiscordBot/Discord/Commands/Restart.cs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Others;
|
||||||
|
using PluginManager.Others.Permissions;
|
||||||
|
using DiscordLibCommands = Discord.Commands;
|
||||||
|
using DiscordLib = Discord;
|
||||||
|
using OperatingSystem = PluginManager.Others.OperatingSystem;
|
||||||
|
|
||||||
|
namespace DiscordBot.Discord.Commands;
|
||||||
|
|
||||||
|
internal class Restart : DBCommand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Command name
|
||||||
|
/// </summary>
|
||||||
|
public string Command => "restart";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command Description
|
||||||
|
/// </summary>
|
||||||
|
public string Description => "Restart the bot";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command usage
|
||||||
|
/// </summary>
|
||||||
|
public string Usage => "restart [-p | -c | -args | -cmd] <args>";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the command can be used <inheritdoca DM <see cref="IChannel" />/>
|
||||||
|
/// </summary>
|
||||||
|
public bool canUseDM => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the command can be used in a server
|
||||||
|
/// </summary>
|
||||||
|
public bool canUseServer => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the command require administrator to be executed
|
||||||
|
/// </summary>
|
||||||
|
public bool requireAdmin => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The main body of the command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The command context</param>
|
||||||
|
/// <param name="message">The command message</param>
|
||||||
|
/// <param name="client">The discord bot client</param>
|
||||||
|
/// <param name="isDM">True if the message was sent from a DM channel, false otherwise</param>
|
||||||
|
public async void Execute(DiscordLibCommands.SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
|
||||||
|
{
|
||||||
|
if (!(message.Author as SocketGuildUser).hasPermission(DiscordLib.GuildPermission.Administrator)) return;
|
||||||
|
var args = Functions.GetArguments(message);
|
||||||
|
var OS = Functions.GetOperatingSystem();
|
||||||
|
if (args.Count == 0)
|
||||||
|
{
|
||||||
|
switch (OS)
|
||||||
|
{
|
||||||
|
case OperatingSystem.WINDOWS:
|
||||||
|
Process.Start("./DiscordBot.exe");
|
||||||
|
break;
|
||||||
|
case OperatingSystem.LINUX:
|
||||||
|
case OperatingSystem.MAC_OS:
|
||||||
|
Process.Start("./DiscordBot");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (args[0])
|
||||||
|
{
|
||||||
|
case "-p":
|
||||||
|
case "-poweroff":
|
||||||
|
case "-c":
|
||||||
|
case "-close":
|
||||||
|
Environment.Exit(0);
|
||||||
|
break;
|
||||||
|
case "-cmd":
|
||||||
|
case "-args":
|
||||||
|
var cmd = "--args";
|
||||||
|
|
||||||
|
if (args.Count > 1)
|
||||||
|
for (var i = 1; i < args.Count; i++)
|
||||||
|
cmd += $" {args[i]}";
|
||||||
|
|
||||||
|
|
||||||
|
switch (OS)
|
||||||
|
{
|
||||||
|
case OperatingSystem.WINDOWS:
|
||||||
|
Functions.WriteLogFile("Restarting the bot with the following arguments: \"" + cmd + "\"");
|
||||||
|
Process.Start("./DiscordBot.exe", cmd);
|
||||||
|
break;
|
||||||
|
case OperatingSystem.LINUX:
|
||||||
|
//case PluginManager.Others.OperatingSystem.MAC_OS: ?? - not tested
|
||||||
|
Process.Start("./DiscordBot", cmd);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Environment.Exit(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await context.Channel.SendMessageAsync("Invalid argument. Use `help restart` to see the usage.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
97
DiscordBot/Discord/Commands/Settings.cs
Normal file
97
DiscordBot/Discord/Commands/Settings.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using System;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
|
||||||
|
namespace DiscordBot.Discord.Commands;
|
||||||
|
|
||||||
|
internal class Settings : DBCommand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Command name
|
||||||
|
/// </summary>
|
||||||
|
public string Command => "set";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command Description
|
||||||
|
/// </summary>
|
||||||
|
public string Description => "This command allows you change all settings. Use \"set help\" to show details";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command usage
|
||||||
|
/// </summary>
|
||||||
|
public string Usage => "set [keyword] [new Value]";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the command can be used <inheritdoca DM <see cref="IChannel" />/>
|
||||||
|
/// </summary>
|
||||||
|
public bool canUseDM => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the command can be used in a server
|
||||||
|
/// </summary>
|
||||||
|
public bool canUseServer => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the command require administrator to be executed
|
||||||
|
/// </summary>
|
||||||
|
public bool requireAdmin => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The main body of the command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The command context</param>
|
||||||
|
/// <param name="message">The command message</param>
|
||||||
|
/// <param name="client">The discord bot client</param>
|
||||||
|
/// <param name="isDM">True if the message was sent from a DM channel, false otherwise</param>
|
||||||
|
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
|
||||||
|
{
|
||||||
|
var channel = message.Channel;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = message.Content;
|
||||||
|
var data = content.Split(' ');
|
||||||
|
var keyword = data[1];
|
||||||
|
if (keyword.ToLower() == "help")
|
||||||
|
{
|
||||||
|
await channel.SendMessageAsync("set token [new value] -- set the value of the new token (require restart)");
|
||||||
|
await channel.SendMessageAsync("set prefix [new value] -- set the value of the new preifx (require restart)");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (keyword.ToLower())
|
||||||
|
{
|
||||||
|
case "token":
|
||||||
|
if (data.Length != 3)
|
||||||
|
{
|
||||||
|
await channel.SendMessageAsync("Invalid token !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.SetValue("token", data[2]);
|
||||||
|
break;
|
||||||
|
case "prefix":
|
||||||
|
if (data.Length != 3)
|
||||||
|
{
|
||||||
|
await channel.SendMessageAsync("Invalid token !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.SetValue("token", data[2]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await channel.SendMessageAsync("Restart required ...");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
await channel.SendMessageAsync("Unknown usage to this command !\nUsage: " + Usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
149
DiscordBot/Discord/Core/Boot.cs
Normal file
149
DiscordBot/Discord/Core/Boot.cs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager;
|
||||||
|
using static PluginManager.Others.Functions;
|
||||||
|
|
||||||
|
namespace DiscordBot.Discord.Core;
|
||||||
|
|
||||||
|
internal class Boot
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The bot prefix
|
||||||
|
/// </summary>
|
||||||
|
public readonly string botPrefix;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The bot token
|
||||||
|
/// </summary>
|
||||||
|
public readonly string botToken;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The bot client
|
||||||
|
/// </summary>
|
||||||
|
public DiscordSocketClient client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The bot command handler
|
||||||
|
/// </summary>
|
||||||
|
private CommandHandler commandServiceHandler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The command service
|
||||||
|
/// </summary>
|
||||||
|
private CommandService service;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The main Boot constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="botToken">The bot token</param>
|
||||||
|
/// <param name="botPrefix">The bot prefix</param>
|
||||||
|
public Boot(string botToken, string botPrefix)
|
||||||
|
{
|
||||||
|
this.botPrefix = botPrefix;
|
||||||
|
this.botToken = botToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the bot is ready
|
||||||
|
/// </summary>
|
||||||
|
/// <value> true if the bot is ready, othwerwise false </value>
|
||||||
|
public bool isReady { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The start method for the bot. This method is used to load the bot
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Task</returns>
|
||||||
|
public async Task Awake()
|
||||||
|
{
|
||||||
|
client = new DiscordSocketClient();
|
||||||
|
service = new CommandService();
|
||||||
|
|
||||||
|
CommonTasks();
|
||||||
|
|
||||||
|
await client.LoginAsync(TokenType.Bot, botToken);
|
||||||
|
await client.StartAsync();
|
||||||
|
|
||||||
|
commandServiceHandler = new CommandHandler(client, service, botPrefix);
|
||||||
|
await commandServiceHandler.InstallCommandsAsync();
|
||||||
|
|
||||||
|
await Task.Delay(2000);
|
||||||
|
while (!isReady) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CommonTasks()
|
||||||
|
{
|
||||||
|
if (client == null) return;
|
||||||
|
client.LoggedOut += Client_LoggedOut;
|
||||||
|
client.Log += Log;
|
||||||
|
client.LoggedIn += LoggedIn;
|
||||||
|
client.Ready += Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Client_LoggedOut()
|
||||||
|
{
|
||||||
|
WriteLogFile("Successfully Logged Out");
|
||||||
|
Log(new LogMessage(LogSeverity.Info, "Boot", "Successfully logged out from discord !"));
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Ready()
|
||||||
|
{
|
||||||
|
Console.Title = "ONLINE";
|
||||||
|
isReady = true;
|
||||||
|
|
||||||
|
new Thread(() =>
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Config.SaveConfig();
|
||||||
|
Thread.Sleep(10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).Start();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task LoggedIn()
|
||||||
|
{
|
||||||
|
Console.Title = "CONNECTED";
|
||||||
|
WriteLogFile("The bot has been logged in at " + DateTime.Now.ToShortDateString() + " (" +
|
||||||
|
DateTime.Now.ToShortTimeString() + ")"
|
||||||
|
);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Log(LogMessage message)
|
||||||
|
{
|
||||||
|
switch (message.Severity)
|
||||||
|
{
|
||||||
|
case LogSeverity.Error:
|
||||||
|
case LogSeverity.Critical:
|
||||||
|
WriteErrFile(message.Message);
|
||||||
|
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine("[ERROR] " + message.Message);
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LogSeverity.Info:
|
||||||
|
case LogSeverity.Debug:
|
||||||
|
WriteLogFile(message.Message);
|
||||||
|
|
||||||
|
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||||
|
Console.WriteLine("[INFO] " + message.Message);
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
131
DiscordBot/Discord/Core/CommandHandler.cs
Normal file
131
DiscordBot/Discord/Core/CommandHandler.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager.Loaders;
|
||||||
|
using PluginManager.Others;
|
||||||
|
using PluginManager.Others.Permissions;
|
||||||
|
|
||||||
|
namespace DiscordBot.Discord.Core;
|
||||||
|
|
||||||
|
internal class CommandHandler
|
||||||
|
{
|
||||||
|
private readonly string botPrefix;
|
||||||
|
private readonly DiscordSocketClient client;
|
||||||
|
private readonly CommandService commandService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command handler constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The discord bot client</param>
|
||||||
|
/// <param name="commandService">The discord bot command service</param>
|
||||||
|
/// <param name="botPrefix">The prefix to watch for</param>
|
||||||
|
public CommandHandler(DiscordSocketClient client, CommandService commandService, string botPrefix)
|
||||||
|
{
|
||||||
|
this.client = client;
|
||||||
|
this.commandService = commandService;
|
||||||
|
this.botPrefix = botPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The method to initialize all commands
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task InstallCommandsAsync()
|
||||||
|
{
|
||||||
|
client.MessageReceived += MessageHandler;
|
||||||
|
await commandService.AddModulesAsync(Assembly.GetEntryAssembly(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The message handler for the bot
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Message">The message got from the user in discord chat</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task MessageHandler(SocketMessage Message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Message as SocketUserMessage == null) return;
|
||||||
|
|
||||||
|
var message = Message as SocketUserMessage;
|
||||||
|
|
||||||
|
if (message == null) return;
|
||||||
|
|
||||||
|
if (!message.Content.StartsWith(botPrefix)) return;
|
||||||
|
|
||||||
|
var argPos = 0;
|
||||||
|
|
||||||
|
if (message.HasMentionPrefix(client.CurrentUser, ref argPos))
|
||||||
|
{
|
||||||
|
await message.Channel.SendMessageAsync("Can not exec mentioned commands !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.Author.IsBot) return;
|
||||||
|
|
||||||
|
var context = new SocketCommandContext(client, message);
|
||||||
|
|
||||||
|
await commandService.ExecuteAsync(
|
||||||
|
context,
|
||||||
|
argPos,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
var plugin = PluginLoader.Commands!.Where(p => p.Command == message.Content.Split(' ')[0].Substring(botPrefix.Length)).FirstOrDefault();
|
||||||
|
|
||||||
|
|
||||||
|
if (plugin != null)
|
||||||
|
{
|
||||||
|
if (message.Channel == await message.Author.CreateDMChannelAsync())
|
||||||
|
{
|
||||||
|
if (plugin.canUseDM)
|
||||||
|
{
|
||||||
|
if (plugin.requireAdmin)
|
||||||
|
{
|
||||||
|
if (message.Author.isAdmin())
|
||||||
|
{
|
||||||
|
plugin.Execute(context, message, client, true);
|
||||||
|
Functions.WriteLogFile($"[{message.Author.Id}] Executed command (DM) : " + plugin.Command);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await message.Channel.SendMessageAsync("This command is for administrators only !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.Execute(context, message, client, true);
|
||||||
|
Functions.WriteLogFile($"[{message.Author.Id}] Executed command (DM) : " + plugin.Command);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await message.Channel.SendMessageAsync("This command is not for DMs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.canUseServer)
|
||||||
|
{
|
||||||
|
if (plugin.requireAdmin)
|
||||||
|
{
|
||||||
|
if (message.Author.isAdmin())
|
||||||
|
{
|
||||||
|
plugin.Execute(context, message, client, false);
|
||||||
|
Functions.WriteLogFile($"[{message.Author.Id}] Executed command : " + plugin.Command);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await message.Channel.SendMessageAsync("This command is for administrators only !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.Execute(context, message, client, false);
|
||||||
|
Functions.WriteLogFile($"[{message.Author.Id}] Executed command : " + plugin.Command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
DiscordBot/DiscordBot.csproj
Normal file
48
DiscordBot/DiscordBot.csproj
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<ApplicationIcon />
|
||||||
|
<StartupObject />
|
||||||
|
<SignAssembly>False</SignAssembly>
|
||||||
|
<IsPublishable>True</IsPublishable>
|
||||||
|
<AssemblyVersion>1.0.0.1</AssemblyVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Data\**" />
|
||||||
|
<Compile Remove="obj\**" />
|
||||||
|
<Compile Remove="Output\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Remove="Data\**" />
|
||||||
|
<EmbeddedResource Remove="obj\**" />
|
||||||
|
<EmbeddedResource Remove="Output\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="Data\**" />
|
||||||
|
<None Remove="obj\**" />
|
||||||
|
<None Remove="Output\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Discord.Net" Version="3.7.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\PluginManager\PluginManager.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
312
DiscordBot/Program.cs
Normal file
312
DiscordBot/Program.cs
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using DiscordBot.Discord.Core;
|
||||||
|
using PluginManager;
|
||||||
|
using PluginManager.Items;
|
||||||
|
using PluginManager.Online;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace DiscordBot;
|
||||||
|
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
private static bool loadPluginsOnStartup;
|
||||||
|
private static bool listPluginsAtStartup;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
[Obsolete]
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory("./Data/Resources");
|
||||||
|
Directory.CreateDirectory("./Data/Plugins/Commands");
|
||||||
|
Directory.CreateDirectory("./Data/Plugins/Events");
|
||||||
|
PreLoadComponents().Wait();
|
||||||
|
|
||||||
|
if (!Config.ContainsKey("token") || Config.GetValue<string>("token") == null || Config.GetValue<string>("token")?.Length != 70)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Please insert your token");
|
||||||
|
Console.Write("Token = ");
|
||||||
|
var token = Console.ReadLine();
|
||||||
|
if (token?.Length == 59 || token?.Length == 70)
|
||||||
|
Config.AddValueToVariables("token", token, true);
|
||||||
|
else
|
||||||
|
Console.WriteLine("Invalid token");
|
||||||
|
|
||||||
|
Console.WriteLine("Please insert your prefix (max. 1 character long):");
|
||||||
|
Console.WriteLine("For a prefix longer then one character, the first character will be saved and the others will be ignored.\n No spaces or numbers allowed");
|
||||||
|
Console.Write("Prefix = ");
|
||||||
|
var prefix = Console.ReadLine()![0];
|
||||||
|
|
||||||
|
if (prefix == ' ' || char.IsDigit(prefix)) return;
|
||||||
|
Config.AddValueToVariables("prefix", prefix.ToString(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Config.ContainsKey("prefix") || Config.GetValue<string>("prefix") == default)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Please insert your prefix (max. 1 character long):");
|
||||||
|
Console.WriteLine("For a prefix longer then one character, the first character will be saved and the others will be ignored.\n No spaces or numbers allowed");
|
||||||
|
Console.Write("Prefix = ");
|
||||||
|
var prefix = Console.ReadLine()![0];
|
||||||
|
if (prefix == ' ') return;
|
||||||
|
Config.AddValueToVariables("prefix", prefix.ToString(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HandleInput(args).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The main loop for the discord bot
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discordbooter">The discord booter used to start the application</param>
|
||||||
|
private static Task NoGUI(Boot discordbooter)
|
||||||
|
{
|
||||||
|
var consoleCommandsHandler = new ConsoleCommandsHandler(discordbooter.client);
|
||||||
|
if (loadPluginsOnStartup) consoleCommandsHandler.HandleCommand("lp");
|
||||||
|
if (listPluginsAtStartup) consoleCommandsHandler.HandleCommand("listplugs");
|
||||||
|
|
||||||
|
Config.SaveConfig();
|
||||||
|
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
var cmd = Console.ReadLine();
|
||||||
|
if (!consoleCommandsHandler.HandleCommand(cmd))
|
||||||
|
Console.WriteLine("Failed to run command " + cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start the bot without user interface
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns the boot loader for the Discord Bot</returns>
|
||||||
|
private static async Task<Boot> StartNoGUI()
|
||||||
|
{
|
||||||
|
Console.Clear();
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
|
|
||||||
|
List<string> startupMessageList = await ServerCom.ReadTextFromFile("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/StartupMessage");
|
||||||
|
|
||||||
|
foreach (var message in startupMessageList) Console.WriteLine(message);
|
||||||
|
|
||||||
|
Console.WriteLine($"Running on version: {Config.GetValue<string>("Version") ?? System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()}");
|
||||||
|
Console.WriteLine($"Git URL: {Config.GetValue<string>("GitURL") ?? " Could not find Git URL"}");
|
||||||
|
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.WriteLine($"============================ LOG ============================");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var token = Config.GetValue<string>("token");
|
||||||
|
var prefix = Config.GetValue<string>("prefix");
|
||||||
|
|
||||||
|
var discordbooter = new Boot(token, prefix);
|
||||||
|
await discordbooter.Awake();
|
||||||
|
return discordbooter;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear folder
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="d">Directory path</param>
|
||||||
|
private static Task ClearFolder(string d)
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(d);
|
||||||
|
var fileNumb = files.Length;
|
||||||
|
for (var i = 0; i < fileNumb; i++)
|
||||||
|
{
|
||||||
|
File.Delete(files[i]);
|
||||||
|
Console.WriteLine("Deleting : " + files[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle user input arguments from the startup of the application
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The arguments</param>
|
||||||
|
private static async Task HandleInput(string[] args)
|
||||||
|
{
|
||||||
|
var len = args.Length;
|
||||||
|
|
||||||
|
if (len == 3 && args[0] == "/download")
|
||||||
|
{
|
||||||
|
var url = args[1];
|
||||||
|
var location = args[2];
|
||||||
|
|
||||||
|
await ServerCom.DownloadFileAsync(url, location);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0 && (args.Contains("--cmd") || args.Contains("--args") || args.Contains("--nomessage")))
|
||||||
|
{
|
||||||
|
if (args.Contains("lp") || args.Contains("loadplugins")) loadPluginsOnStartup = true;
|
||||||
|
if (args.Contains("listplugs")) listPluginsAtStartup = true;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (len == 0 || (args[0] != "--exec" && args[0] != "--execute"))
|
||||||
|
{
|
||||||
|
var b = await StartNoGUI();
|
||||||
|
await NoGUI(b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
|
Console.WriteLine("Execute command interface noGUI\n\n");
|
||||||
|
Console.WriteLine(
|
||||||
|
"\tCommand name\t\t\t\tDescription\n" +
|
||||||
|
"-- help | -help\t\t ------ \tDisplay the help message\n" +
|
||||||
|
"--reset-full\t\t ------ \tReset all files (clear files)\n" +
|
||||||
|
"--reset-logs\t\t ------ \tClear up the output folder\n" +
|
||||||
|
"--start\t\t ------ \tStart the bot\n" +
|
||||||
|
"exit\t\t\t ------ \tClose the application"
|
||||||
|
);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.Write("> ");
|
||||||
|
var message = Console.ReadLine().Split(' ');
|
||||||
|
|
||||||
|
switch (message[0])
|
||||||
|
{
|
||||||
|
case "--help":
|
||||||
|
case "-help":
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
|
Console.WriteLine(
|
||||||
|
"\tCommand name\t\t\t\tDescription\n" +
|
||||||
|
"-- help | -help\t\t ------ \tDisplay the help message\n" +
|
||||||
|
"--reset-full\t\t ------ \tReset all files (clear files)\n" +
|
||||||
|
"--reset-settings\t ------ \tReset only bot settings\n" +
|
||||||
|
"--reset-logs\t\t ------ \tClear up the output folder\n" +
|
||||||
|
"--start\t\t ------ \tStart the bot\n" +
|
||||||
|
"exit\t\t\t ------ \tClose the application"
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "--reset-full":
|
||||||
|
await ClearFolder("./Data/Resources/");
|
||||||
|
await ClearFolder("./Output/Logs/");
|
||||||
|
await ClearFolder("./Output/Errors");
|
||||||
|
await ClearFolder("./Data/Languages/");
|
||||||
|
await ClearFolder("./Data/Plugins/Commands");
|
||||||
|
await ClearFolder("./Data/Plugins/Events");
|
||||||
|
Console.WriteLine("Successfully cleared all folders");
|
||||||
|
break;
|
||||||
|
case "--reset-logs":
|
||||||
|
await ClearFolder("./Output/Logs");
|
||||||
|
await ClearFolder("./Output/Errors");
|
||||||
|
Console.WriteLine("Successfully cleard logs folder");
|
||||||
|
break;
|
||||||
|
case "--exit":
|
||||||
|
case "exit":
|
||||||
|
Environment.Exit(0);
|
||||||
|
break;
|
||||||
|
case "--start":
|
||||||
|
var booter = await StartNoGUI();
|
||||||
|
await NoGUI(booter);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Console.WriteLine("Failed to execute command " + message[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task PreLoadComponents()
|
||||||
|
{
|
||||||
|
await Config.LoadConfig();
|
||||||
|
if (Config.ContainsKey("DeleteLogsAtStartup"))
|
||||||
|
if (Config.GetValue<bool>("DeleteLogsAtStartup"))
|
||||||
|
foreach (var file in Directory.GetFiles("./Output/Logs/"))
|
||||||
|
File.Delete(file);
|
||||||
|
List<string> OnlineDefaultKeys = await ServerCom.ReadTextFromFile("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/SetupKeys");
|
||||||
|
|
||||||
|
Config.PluginConfig.Load();
|
||||||
|
|
||||||
|
if (!Config.ContainsKey("Version"))
|
||||||
|
Config.AddValueToVariables("Version", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(), false);
|
||||||
|
else
|
||||||
|
Config.SetValue("Version", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
||||||
|
|
||||||
|
foreach (var key in OnlineDefaultKeys)
|
||||||
|
{
|
||||||
|
if (key.Length <= 3 || !key.Contains(' ')) continue;
|
||||||
|
string[] s = key.Split(' ');
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Config.GetAndAddValueToVariable(s[0], s[1], s[2].Equals("true", StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Functions.WriteErrFile(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> onlineSettingsList = await ServerCom.ReadTextFromFile("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/OnlineData");
|
||||||
|
foreach (var key in onlineSettingsList)
|
||||||
|
{
|
||||||
|
if (key.Length <= 3 || !key.Contains(' ')) continue;
|
||||||
|
|
||||||
|
string[] s = key.Split(' ');
|
||||||
|
switch (s[0])
|
||||||
|
{
|
||||||
|
case "CurrentVersion":
|
||||||
|
string newVersion = s[1];
|
||||||
|
if (!newVersion.Equals(Config.GetValue<string>("Version")))
|
||||||
|
{
|
||||||
|
Console.WriteLine("A new version has been released on github page.");
|
||||||
|
Console.WriteLine("Download the new version using the following link wrote in yellow");
|
||||||
|
Console_Utilities.WriteColorText("&y" + Config.GetValue<string>("GitURL") + "&c");
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Your product will work just fine on this outdated version, but an update is recommended.\n" +
|
||||||
|
"From now on, this version is no longer supported"
|
||||||
|
);
|
||||||
|
Console_Utilities.WriteColorText("&rUse at your own risk&c");
|
||||||
|
|
||||||
|
Console_Utilities.WriteColorText("&mCurrent Version: " + Config.GetValue<string>("Version") + "&c");
|
||||||
|
Console_Utilities.WriteColorText("&gNew Version: " + newVersion + "&c");
|
||||||
|
|
||||||
|
Console.WriteLine("\n\n");
|
||||||
|
await Task.Delay(1000);
|
||||||
|
|
||||||
|
int waitTime = 20; //wait time to proceed
|
||||||
|
|
||||||
|
Console.Write($"The bot will start in {waitTime} seconds");
|
||||||
|
while (waitTime > 0)
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
waitTime--;
|
||||||
|
Console.SetCursorPosition("The bot will start in ".Length, Console.CursorTop);
|
||||||
|
Console.Write(" ");
|
||||||
|
Console.SetCursorPosition("The bot will start in ".Length, Console.CursorTop);
|
||||||
|
Console.Write(waitTime + " seconds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Config.SaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
using DiscordBotCore.Logging;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Configuration;
|
|
||||||
|
|
||||||
public class Configuration : ConfigurationBase
|
|
||||||
{
|
|
||||||
private readonly bool _EnableAutoAddOnGetWithDefault;
|
|
||||||
private Configuration(ILogger logger, string diskLocation, bool enableAutoAddOnGetWithDefault): base(logger, diskLocation)
|
|
||||||
{
|
|
||||||
_EnableAutoAddOnGetWithDefault = enableAutoAddOnGetWithDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task SaveToFile()
|
|
||||||
{
|
|
||||||
var json = JsonConvert.SerializeObject(_InternalDictionary, Formatting.Indented);
|
|
||||||
await File.WriteAllTextAsync(_DiskLocation, json);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override T Get<T>(string key, T defaultValue)
|
|
||||||
{
|
|
||||||
T value = base.Get(key, defaultValue);
|
|
||||||
|
|
||||||
if (_EnableAutoAddOnGetWithDefault && value.Equals(defaultValue))
|
|
||||||
{
|
|
||||||
Add(key, defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override List<T> GetList<T>(string key, List<T> defaultValue)
|
|
||||||
{
|
|
||||||
List<T> value = base.GetList(key, defaultValue);
|
|
||||||
|
|
||||||
if (_EnableAutoAddOnGetWithDefault && value.All(defaultValue.Contains))
|
|
||||||
{
|
|
||||||
Add(key, defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void LoadFromFile()
|
|
||||||
{
|
|
||||||
if (!File.Exists(_DiskLocation))
|
|
||||||
{
|
|
||||||
SaveToFile().Wait();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string jsonContent = File.ReadAllText(_DiskLocation);
|
|
||||||
var jObject = JsonConvert.DeserializeObject<JObject>(jsonContent);
|
|
||||||
|
|
||||||
if (jObject is null)
|
|
||||||
{
|
|
||||||
SaveToFile().Wait();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_InternalDictionary.Clear();
|
|
||||||
|
|
||||||
foreach (var kvp in jObject)
|
|
||||||
{
|
|
||||||
AddPairToDictionary(kvp, _InternalDictionary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddPairToDictionary(KeyValuePair<string, JToken> kvp, IDictionary<string, object> dict)
|
|
||||||
{
|
|
||||||
if (kvp.Value is JObject nestedJObject)
|
|
||||||
{
|
|
||||||
dict[kvp.Key] = nestedJObject.ToObject<Dictionary<string, object>>();
|
|
||||||
|
|
||||||
foreach (var nestedKvp in nestedJObject)
|
|
||||||
{
|
|
||||||
AddPairToDictionary(nestedKvp, dict[kvp.Key] as Dictionary<string, object>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (kvp.Value is JArray nestedJArray)
|
|
||||||
{
|
|
||||||
dict[kvp.Key] = nestedJArray.ToObject<List<object>>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (kvp.Value.Type == JTokenType.Integer)
|
|
||||||
dict[kvp.Key] = kvp.Value.Value<int>();
|
|
||||||
else if (kvp.Value.Type == JTokenType.Float)
|
|
||||||
dict[kvp.Key] = kvp.Value.Value<float>();
|
|
||||||
else if (kvp.Value.Type == JTokenType.Boolean)
|
|
||||||
dict[kvp.Key] = kvp.Value.Value<bool>();
|
|
||||||
else if (kvp.Value.Type == JTokenType.String)
|
|
||||||
dict[kvp.Key] = kvp.Value.Value<string>();
|
|
||||||
else if (kvp.Value.Type == JTokenType.Date)
|
|
||||||
dict[kvp.Key] = kvp.Value.Value<DateTime>();
|
|
||||||
else
|
|
||||||
dict[kvp.Key] = kvp.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new Settings Dictionary from a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="baseFile">The file location</param>
|
|
||||||
/// <param name="enableAutoAddOnGetWithDefault">Set this to true if you want to update the dictionary with default values on get</param>
|
|
||||||
public static Configuration CreateFromFile(ILogger logger, string baseFile, bool enableAutoAddOnGetWithDefault)
|
|
||||||
{
|
|
||||||
var settings = new Configuration(logger, baseFile, enableAutoAddOnGetWithDefault);
|
|
||||||
settings.LoadFromFile();
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
using System.Collections;
|
|
||||||
using System.Net.Mime;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Configuration;
|
|
||||||
|
|
||||||
public abstract class ConfigurationBase : IConfiguration
|
|
||||||
{
|
|
||||||
protected readonly IDictionary<string, object> _InternalDictionary = new Dictionary<string, object>();
|
|
||||||
protected readonly string _DiskLocation;
|
|
||||||
protected readonly ILogger _Logger;
|
|
||||||
|
|
||||||
protected ConfigurationBase(ILogger logger, string diskLocation)
|
|
||||||
{
|
|
||||||
this._DiskLocation = diskLocation;
|
|
||||||
this._Logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Add(string key, object? value)
|
|
||||||
{
|
|
||||||
if (_InternalDictionary.ContainsKey(key))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (value is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_InternalDictionary.Add(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Set(string key, object value)
|
|
||||||
{
|
|
||||||
_InternalDictionary[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual object Get(string key)
|
|
||||||
{
|
|
||||||
return _InternalDictionary[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual T Get<T>(string key, T defaulobject)
|
|
||||||
{
|
|
||||||
if (_InternalDictionary.TryGetValue(key, out var value))
|
|
||||||
{
|
|
||||||
return (T)Convert.ChangeType(value, typeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaulobject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual T? Get<T>(string key)
|
|
||||||
{
|
|
||||||
if (_InternalDictionary.TryGetValue(key, out var value))
|
|
||||||
{
|
|
||||||
return (T)Convert.ChangeType(value, typeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IDictionary<TSubKey, TSubValue> GetDictionary<TSubKey, TSubValue>(string key)
|
|
||||||
{
|
|
||||||
if (_InternalDictionary.TryGetValue(key, out var value))
|
|
||||||
{
|
|
||||||
if (value is not IDictionary)
|
|
||||||
{
|
|
||||||
throw new Exception("The value is not a dictionary");
|
|
||||||
}
|
|
||||||
|
|
||||||
var dictionary = new Dictionary<TSubKey, TSubValue>();
|
|
||||||
foreach (DictionaryEntry item in (IDictionary)value)
|
|
||||||
{
|
|
||||||
dictionary.Add((TSubKey)Convert.ChangeType(item.Key, typeof(TSubKey)), (TSubValue)Convert.ChangeType(item.Value, typeof(TSubValue)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dictionary;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Dictionary<TSubKey, TSubValue>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual List<T> GetList<T>(string key, List<T> defaulobject)
|
|
||||||
{
|
|
||||||
if(_InternalDictionary.TryGetValue(key, out var value))
|
|
||||||
{
|
|
||||||
if (value is not IList)
|
|
||||||
{
|
|
||||||
throw new Exception("The value is not a list");
|
|
||||||
}
|
|
||||||
|
|
||||||
var list = new List<T>();
|
|
||||||
foreach (object? item in (IList)value)
|
|
||||||
{
|
|
||||||
list.Add((T)Convert.ChangeType(item, typeof(T)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Logger.Log($"Key '{key}' not found in settings dictionary. Adding default value.", LogType.Warning);
|
|
||||||
|
|
||||||
return defaulobject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Remove(string key)
|
|
||||||
{
|
|
||||||
_InternalDictionary.Remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
|
||||||
{
|
|
||||||
return _InternalDictionary.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Clear()
|
|
||||||
{
|
|
||||||
_InternalDictionary.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool ContainsKey(string key)
|
|
||||||
{
|
|
||||||
return _InternalDictionary.ContainsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IEnumerable<KeyValuePair<string, object>> Where(Func<KeyValuePair<string, object>, bool> predicate)
|
|
||||||
{
|
|
||||||
return _InternalDictionary.Where(predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IEnumerable<KeyValuePair<string, object>> Where(Func<KeyValuePair<string, object>, int, bool> predicate)
|
|
||||||
{
|
|
||||||
return _InternalDictionary.Where(predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IEnumerable<TResult> Where<TResult>(Func<KeyValuePair<string, object>, TResult> selector)
|
|
||||||
{
|
|
||||||
return _InternalDictionary.Select(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IEnumerable<TResult> Where<TResult>(Func<KeyValuePair<string, object>, int, TResult> selector)
|
|
||||||
{
|
|
||||||
return _InternalDictionary.Select(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual KeyValuePair<string, object> FirstOrDefault(Func<KeyValuePair<string, object>, bool> predicate)
|
|
||||||
{
|
|
||||||
return _InternalDictionary.FirstOrDefault(predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual KeyValuePair<string, object> FirstOrDefault()
|
|
||||||
{
|
|
||||||
return _InternalDictionary.FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool ContainsAllKeys(params string[] keys)
|
|
||||||
{
|
|
||||||
return keys.All(ContainsKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool TryGetValue(string key, out object? value)
|
|
||||||
{
|
|
||||||
return _InternalDictionary.TryGetValue(key, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Task SaveToFile();
|
|
||||||
|
|
||||||
public abstract void LoadFromFile();
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<Platforms>AnyCPU;x64;ARM64</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Logging\DiscordBotCore.Logging.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
namespace DiscordBotCore.Configuration;
|
|
||||||
|
|
||||||
public interface IConfiguration
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Adds an element to the custom settings dictionary
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">The key</param>
|
|
||||||
/// <param name="value">The value</param>
|
|
||||||
void Add(string key, object value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the value of a key in the custom settings dictionary
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">The key</param>
|
|
||||||
/// <param name="value">The value</param>
|
|
||||||
void Set(string key, object value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value of a key in the custom settings dictionary. If the T type is different then the object type, it will try to convert it.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">The key</param>
|
|
||||||
/// <param name="defaultObject">The default value to be returned if the searched value is not found</param>
|
|
||||||
/// <typeparam name="T">The type of the returned value</typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
T Get<T>(string key, T defaultObject);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value of a key in the custom settings dictionary. If the T type is different then the object type, it will try to convert it.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">The key</param>
|
|
||||||
/// <typeparam name="T">The type of the returned value</typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
T? Get<T>(string key);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a list of values from the custom settings dictionary
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">The key</param>
|
|
||||||
/// <param name="defaultObject">The default list to be returned if nothing is found</param>
|
|
||||||
/// <typeparam name="T">The type of the returned value</typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
List<T> GetList<T>(string key, List<T> defaultObject);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a key from the custom settings dictionary
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">The key</param>
|
|
||||||
void Remove(string key);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the enumerator of the custom settings dictionary
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
IEnumerator<KeyValuePair<string, object>> GetEnumerator();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clear the custom settings dictionary
|
|
||||||
/// </summary>
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if the custom settings dictionary contains a key
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">The key</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool ContainsKey(string key);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter the custom settings dictionary based on a predicate
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="predicate">The predicate</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
IEnumerable<KeyValuePair<string, object>> Where(Func<KeyValuePair<string, object>, bool> predicate);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter the custom settings dictionary based on a predicate
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="predicate">The predicate</param>
|
|
||||||
IEnumerable<KeyValuePair<string, object>> Where(Func<KeyValuePair<string, object>, int, bool> predicate);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter the custom settings dictionary based on a predicate
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="selector">The predicate</param>
|
|
||||||
IEnumerable<TResult> Where<TResult>(Func<KeyValuePair<string, object>, TResult> selector);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filter the custom settings dictionary based on a predicate
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="selector">The predicate</param>
|
|
||||||
IEnumerable<TResult> Where<TResult>(Func<KeyValuePair<string, object>, int, TResult> selector);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the first element of the custom settings dictionary based on a predicate
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="predicate">The predicate</param>
|
|
||||||
KeyValuePair<string, object> FirstOrDefault(Func<KeyValuePair<string, object>, bool> predicate);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the first element of the custom settings dictionary
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
KeyValuePair<string, object> FirstOrDefault();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the custom settings dictionary contains all the keys
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keys">A list of keys</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool ContainsAllKeys(params string[] keys);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Try to get the value of a key in the custom settings dictionary
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">The key</param>
|
|
||||||
/// <param name="value">The value</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool TryGetValue(string key, out object? value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Save the custom settings dictionary to a file
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task SaveToFile();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Load the custom settings dictionary from a file
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
void LoadFromFile();
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<Platforms>AnyCPU;x64;ARM64</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.3" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,693 +0,0 @@
|
|||||||
using System.Data;
|
|
||||||
using Microsoft.Data.Sqlite;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Database.Sqlite;
|
|
||||||
|
|
||||||
public class SqlDatabase
|
|
||||||
{
|
|
||||||
private readonly SqliteConnection _Connection;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize a SQL connection by specifying its private path
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileName">The path to the database (it is starting from ./Data/Resources/)</param>
|
|
||||||
public SqlDatabase(string fileName)
|
|
||||||
{
|
|
||||||
var connectionString = $"Data Source={fileName}";
|
|
||||||
_Connection = new SqliteConnection(connectionString);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Open the SQL Connection. To close use the Stop() method
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task Open()
|
|
||||||
{
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>
|
|
||||||
/// Insert into a specified table some values
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="values">The values to be inserted (in the correct order and number)</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task InsertAsync(string tableName, params string[] values)
|
|
||||||
{
|
|
||||||
var query = $"INSERT INTO {tableName} VALUES (";
|
|
||||||
for (var i = 0; i < values.Length; i++)
|
|
||||||
{
|
|
||||||
query += $"'{values[i]}'";
|
|
||||||
if (i != values.Length - 1)
|
|
||||||
query += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
query += ")";
|
|
||||||
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
await command.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>
|
|
||||||
/// Insert into a specified table some values
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="values">The values to be inserted (in the correct order and number)</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public void Insert(string tableName, params string[] values)
|
|
||||||
{
|
|
||||||
var query = $"INSERT INTO {tableName} VALUES (";
|
|
||||||
for (var i = 0; i < values.Length; i++)
|
|
||||||
{
|
|
||||||
query += $"'{values[i]}'";
|
|
||||||
if (i != values.Length - 1)
|
|
||||||
query += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
query += ")";
|
|
||||||
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
command.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove every row in a table that has a certain propery
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="KeyName">The column name that the search is made by</param>
|
|
||||||
/// <param name="KeyValue">The value that is searched in the specified column</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task RemoveKeyAsync(string tableName, string KeyName, string KeyValue)
|
|
||||||
{
|
|
||||||
var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
|
|
||||||
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
await command.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove every row in a table that has a certain propery
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="KeyName">The column name that the search is made by</param>
|
|
||||||
/// <param name="KeyValue">The value that is searched in the specified column</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public void RemoveKey(string tableName, string KeyName, string KeyValue)
|
|
||||||
{
|
|
||||||
var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
|
|
||||||
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
command.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if the key exists in the table
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="keyName">The column that the search is made by</param>
|
|
||||||
/// <param name="KeyValue">The value that is searched in the specified column</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> KeyExistsAsync(string tableName, string keyName, string KeyValue)
|
|
||||||
{
|
|
||||||
var query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'";
|
|
||||||
|
|
||||||
if (await ReadDataAsync(query) is not null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if the key exists in the table
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="keyName">The column that the search is made by</param>
|
|
||||||
/// <param name="KeyValue">The value that is searched in the specified column</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool KeyExists(string tableName, string keyName, string KeyValue)
|
|
||||||
{
|
|
||||||
var query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'";
|
|
||||||
|
|
||||||
if (ReadData(query) is not null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set value of a column in a table
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="keyName">The column that the search is made by</param>
|
|
||||||
/// <param name="KeyValue">The value that is searched in the column specified</param>
|
|
||||||
/// <param name="ResultColumnName">The column that has to be modified</param>
|
|
||||||
/// <param name="ResultColumnValue">The new value that will replace the old value from the column specified</param>
|
|
||||||
public async Task SetValueAsync(
|
|
||||||
string tableName, string keyName, string KeyValue, string ResultColumnName,
|
|
||||||
string ResultColumnValue)
|
|
||||||
{
|
|
||||||
if (!await TableExistsAsync(tableName))
|
|
||||||
throw new Exception($"Table {tableName} does not exist");
|
|
||||||
|
|
||||||
await ExecuteAsync(
|
|
||||||
$"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set value of a column in a table
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="keyName">The column that the search is made by</param>
|
|
||||||
/// <param name="KeyValue">The value that is searched in the column specified</param>
|
|
||||||
/// <param name="ResultColumnName">The column that has to be modified</param>
|
|
||||||
/// <param name="ResultColumnValue">The new value that will replace the old value from the column specified</param>
|
|
||||||
public void SetValue(
|
|
||||||
string tableName, string keyName, string KeyValue, string ResultColumnName,
|
|
||||||
string ResultColumnValue)
|
|
||||||
{
|
|
||||||
if (!TableExists(tableName))
|
|
||||||
throw new Exception($"Table {tableName} does not exist");
|
|
||||||
|
|
||||||
Execute($"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get value from a column in a table
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="keyName">The column that the search is made by</param>
|
|
||||||
/// <param name="KeyValue">The value that is searched in the specified column</param>
|
|
||||||
/// <param name="ResultColumnName">The column that has the result</param>
|
|
||||||
/// <returns>A string that has the requested value (can be null if nothing found)</returns>
|
|
||||||
public async Task<string?> GetValueAsync(
|
|
||||||
string tableName, string keyName, string KeyValue,
|
|
||||||
string ResultColumnName)
|
|
||||||
{
|
|
||||||
if (!await TableExistsAsync(tableName))
|
|
||||||
throw new Exception($"Table {tableName} does not exist");
|
|
||||||
|
|
||||||
return await ReadDataAsync($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get value from a column in a table
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="keyName">The column that the search is made by</param>
|
|
||||||
/// <param name="KeyValue">The value that is searched in the specified column</param>
|
|
||||||
/// <param name="ResultColumnName">The column that has the result</param>
|
|
||||||
/// <returns>A string that has the requested value (can be null if nothing found)</returns>
|
|
||||||
public string? GetValue(string tableName, string keyName, string KeyValue, string ResultColumnName)
|
|
||||||
{
|
|
||||||
if (!TableExists(tableName))
|
|
||||||
throw new Exception($"Table {tableName} does not exist");
|
|
||||||
|
|
||||||
return ReadData($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Stop the connection to the SQL Database
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async void Stop()
|
|
||||||
{
|
|
||||||
await _Connection.CloseAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change the structure of a table by adding new columns
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="columns">The columns to be added</param>
|
|
||||||
/// <param name="TYPE">The type of the columns (TEXT, INTEGER, FLOAT, etc)</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task AddColumnsToTableAsync(string tableName, string[] columns, string TYPE = "TEXT")
|
|
||||||
{
|
|
||||||
var command = _Connection.CreateCommand();
|
|
||||||
command.CommandText = $"SELECT * FROM {tableName}";
|
|
||||||
var reader = await command.ExecuteReaderAsync();
|
|
||||||
var tableColumns = new List<string>();
|
|
||||||
for (var i = 0; i < reader.FieldCount; i++)
|
|
||||||
tableColumns.Add(reader.GetName(i));
|
|
||||||
|
|
||||||
foreach (var column in columns)
|
|
||||||
if (!tableColumns.Contains(column))
|
|
||||||
{
|
|
||||||
command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} {TYPE}";
|
|
||||||
await command.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change the structure of a table by adding new columns
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="columns">The columns to be added</param>
|
|
||||||
/// <param name="TYPE">The type of the columns (TEXT, INTEGER, FLOAT, etc)</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public void AddColumnsToTable(string tableName, string[] columns, string TYPE = "TEXT")
|
|
||||||
{
|
|
||||||
var command = _Connection.CreateCommand();
|
|
||||||
command.CommandText = $"SELECT * FROM {tableName}";
|
|
||||||
var reader = command.ExecuteReader();
|
|
||||||
var tableColumns = new List<string>();
|
|
||||||
for (var i = 0; i < reader.FieldCount; i++)
|
|
||||||
tableColumns.Add(reader.GetName(i));
|
|
||||||
|
|
||||||
foreach (var column in columns)
|
|
||||||
if (!tableColumns.Contains(column))
|
|
||||||
{
|
|
||||||
command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} {TYPE}";
|
|
||||||
command.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if a table exists
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <returns>True if the table exists, false if not</returns>
|
|
||||||
public async Task<bool> TableExistsAsync(string tableName)
|
|
||||||
{
|
|
||||||
var cmd = _Connection.CreateCommand();
|
|
||||||
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
|
|
||||||
var result = await cmd.ExecuteScalarAsync();
|
|
||||||
|
|
||||||
if (result == null)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if a table exists
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <returns>True if the table exists, false if not</returns>
|
|
||||||
public bool TableExists(string tableName)
|
|
||||||
{
|
|
||||||
var cmd = _Connection.CreateCommand();
|
|
||||||
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
|
|
||||||
var result = cmd.ExecuteScalar();
|
|
||||||
|
|
||||||
if (result == null)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a table
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="columns">The columns of the table</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task CreateTableAsync(string tableName, params string[] columns)
|
|
||||||
{
|
|
||||||
var cmd = _Connection.CreateCommand();
|
|
||||||
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
|
|
||||||
await cmd.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a table
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">The table name</param>
|
|
||||||
/// <param name="columns">The columns of the table</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public void CreateTable(string tableName, params string[] columns)
|
|
||||||
{
|
|
||||||
var cmd = _Connection.CreateCommand();
|
|
||||||
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Execute a custom query
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query</param>
|
|
||||||
/// <returns>The number of rows that the query modified</returns>
|
|
||||||
public async Task<int> ExecuteAsync(string query)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
var answer = await command.ExecuteNonQueryAsync();
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Execute a custom query
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query</param>
|
|
||||||
/// <returns>The number of rows that the query modified</returns>
|
|
||||||
public int Execute(string query)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
_Connection.Open();
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
var r = command.ExecuteNonQuery();
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read data from the result table and return the first row
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query</param>
|
|
||||||
/// <returns>The result is a string that has all values separated by space character</returns>
|
|
||||||
public async Task<string?> ReadDataAsync(string query)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
var reader = await command.ExecuteReaderAsync();
|
|
||||||
|
|
||||||
var values = new object[reader.FieldCount];
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
reader.GetValues(values);
|
|
||||||
return string.Join<object>(" ", values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read data from the result table and return the first row
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query</param>
|
|
||||||
/// <param name="parameters">The parameters of the query</param>
|
|
||||||
/// <returns>The result is a string that has all values separated by space character</returns>
|
|
||||||
public async Task<string?> ReadDataAsync(string query, params KeyValuePair<string, object>[] parameters)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
foreach (var parameter in parameters)
|
|
||||||
{
|
|
||||||
var p = CreateParameter(parameter);
|
|
||||||
if (p is not null)
|
|
||||||
command.Parameters.Add(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
var reader = await command.ExecuteReaderAsync();
|
|
||||||
|
|
||||||
var values = new object[reader.FieldCount];
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
reader.GetValues(values);
|
|
||||||
return string.Join<object>(" ", values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read data from the result table and return the first row
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query</param>
|
|
||||||
/// <returns>The result is a string that has all values separated by space character</returns>
|
|
||||||
public string? ReadData(string query)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
_Connection.Open();
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
var reader = command.ExecuteReader();
|
|
||||||
|
|
||||||
var values = new object[reader.FieldCount];
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
reader.GetValues(values);
|
|
||||||
return string.Join<object>(" ", values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read data from the result table and return the first row
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query</param>
|
|
||||||
/// <returns>The first row as separated items</returns>
|
|
||||||
public async Task<object[]?> ReadDataArrayAsync(string query)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
var reader = await command.ExecuteReaderAsync();
|
|
||||||
|
|
||||||
var values = new object[reader.FieldCount];
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
reader.GetValues(values);
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<object[]?> ReadDataArrayAsync(string query, params KeyValuePair<string, object>[] parameters)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
foreach (var parameter in parameters)
|
|
||||||
{
|
|
||||||
var p = CreateParameter(parameter);
|
|
||||||
if (p is not null)
|
|
||||||
command.Parameters.Add(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
var reader = await command.ExecuteReaderAsync();
|
|
||||||
|
|
||||||
var values = new object[reader.FieldCount];
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
reader.GetValues(values);
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read data from the result table and return the first row
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query</param>
|
|
||||||
/// <returns>The first row as separated items</returns>
|
|
||||||
public object[]? ReadDataArray(string query)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
_Connection.Open();
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
var reader = command.ExecuteReader();
|
|
||||||
|
|
||||||
var values = new object[reader.FieldCount];
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
reader.GetValues(values);
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read all rows from the result table and return them as a list of string arrays. The string arrays contain the
|
|
||||||
/// values of each row
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query</param>
|
|
||||||
/// <returns>A list of string arrays representing the values that the query returns</returns>
|
|
||||||
public async Task<List<string[]>?> ReadAllRowsAsync(string query)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
var reader = await command.ExecuteReaderAsync();
|
|
||||||
|
|
||||||
if (!reader.HasRows)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
List<string[]> rows = new();
|
|
||||||
while (await reader.ReadAsync())
|
|
||||||
{
|
|
||||||
var values = new string[reader.FieldCount];
|
|
||||||
reader.GetValues(values);
|
|
||||||
rows.Add(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rows.Count == 0) return null;
|
|
||||||
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a parameter for a query
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of the parameter</param>
|
|
||||||
/// <param name="value">The value of the parameter</param>
|
|
||||||
/// <returns>The SQLiteParameter that has the name, value and DBType set according to your inputs</returns>
|
|
||||||
private static SqliteParameter? CreateParameter(string name, object value)
|
|
||||||
{
|
|
||||||
var parameter = new SqliteParameter();
|
|
||||||
parameter.ParameterName = name;
|
|
||||||
parameter.Value = value;
|
|
||||||
|
|
||||||
if (value is string)
|
|
||||||
parameter.DbType = DbType.String;
|
|
||||||
else if (value is int)
|
|
||||||
parameter.DbType = DbType.Int32;
|
|
||||||
else if (value is long)
|
|
||||||
parameter.DbType = DbType.Int64;
|
|
||||||
else if (value is float)
|
|
||||||
parameter.DbType = DbType.Single;
|
|
||||||
else if (value is double)
|
|
||||||
parameter.DbType = DbType.Double;
|
|
||||||
else if (value is bool)
|
|
||||||
parameter.DbType = DbType.Boolean;
|
|
||||||
else if (value is DateTime)
|
|
||||||
parameter.DbType = DbType.DateTime;
|
|
||||||
else if (value is byte[])
|
|
||||||
parameter.DbType = DbType.Binary;
|
|
||||||
else if (value is Guid)
|
|
||||||
parameter.DbType = DbType.Guid;
|
|
||||||
else if (value is decimal)
|
|
||||||
parameter.DbType = DbType.Decimal;
|
|
||||||
else if (value is TimeSpan)
|
|
||||||
parameter.DbType = DbType.Time;
|
|
||||||
else if (value is DateTimeOffset)
|
|
||||||
parameter.DbType = DbType.DateTimeOffset;
|
|
||||||
else if (value is ushort)
|
|
||||||
parameter.DbType = DbType.UInt16;
|
|
||||||
else if (value is uint)
|
|
||||||
parameter.DbType = DbType.UInt32;
|
|
||||||
else if (value is ulong)
|
|
||||||
parameter.DbType = DbType.UInt64;
|
|
||||||
else if (value is sbyte)
|
|
||||||
parameter.DbType = DbType.SByte;
|
|
||||||
else if (value is short)
|
|
||||||
parameter.DbType = DbType.Int16;
|
|
||||||
else if (value is byte)
|
|
||||||
parameter.DbType = DbType.Byte;
|
|
||||||
else if (value is char)
|
|
||||||
parameter.DbType = DbType.StringFixedLength;
|
|
||||||
else if (value is char[])
|
|
||||||
parameter.DbType = DbType.StringFixedLength;
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a parameter for a query. The function automatically detects the type of the value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="parameterValues">The parameter raw inputs. The Key is name and the Value is the value of the parameter</param>
|
|
||||||
/// <returns>The SQLiteParameter that has the name, value and DBType set according to your inputs</returns>
|
|
||||||
private static SqliteParameter? CreateParameter(KeyValuePair<string, object> parameterValues)
|
|
||||||
{
|
|
||||||
return CreateParameter(parameterValues.Key, parameterValues.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Execute a query with parameters
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query to execute</param>
|
|
||||||
/// <param name="parameters">The parameters of the query</param>
|
|
||||||
/// <returns>The number of rows that the query modified in the database</returns>
|
|
||||||
public async Task<int> ExecuteNonQueryAsync(string query, params KeyValuePair<string, object>[] parameters)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
foreach (var parameter in parameters)
|
|
||||||
{
|
|
||||||
var p = CreateParameter(parameter);
|
|
||||||
if (p is not null)
|
|
||||||
command.Parameters.Add(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await command.ExecuteNonQueryAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Execute a query with parameters that returns a specific type of object. The function will return the first row of the result transformed into the specified type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query to execute</param>
|
|
||||||
/// <param name="convertor">The convertor function that will convert each row of the response into an object of <typeparamref name="T"/></param>
|
|
||||||
/// <param name="parameters">The parameters of the query</param>
|
|
||||||
/// <typeparam name="T">The return object type</typeparam>
|
|
||||||
/// <returns>An object of type T that represents the output of the convertor function based on the array of objects that the first row of the result has</returns>
|
|
||||||
public async Task<T?> ReadObjectOfTypeAsync<T>(string query, Func<object[], T> convertor, params KeyValuePair<string, object>[] parameters)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
foreach (var parameter in parameters)
|
|
||||||
{
|
|
||||||
var p = CreateParameter(parameter);
|
|
||||||
if (p is not null)
|
|
||||||
command.Parameters.Add(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
var reader = await command.ExecuteReaderAsync();
|
|
||||||
var values = new object[reader.FieldCount];
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
reader.GetValues(values);
|
|
||||||
return convertor(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Execute a query with parameters that returns a specific type of object. The function will return a list of objects of the specified type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query to execute</param>
|
|
||||||
/// <param name="convertor">The convertor from object[] to T</param>
|
|
||||||
/// <param name="parameters">The parameters of the query</param>
|
|
||||||
/// <typeparam name="T">The expected object type</typeparam>
|
|
||||||
/// <returns>A list of objects of type T that represents each line of the output of the specified query, converted to T</returns>
|
|
||||||
public async Task<List<T>> ReadListOfTypeAsync<T>(string query, Func<object[], T> convertor,
|
|
||||||
params KeyValuePair<string, object>[] parameters)
|
|
||||||
{
|
|
||||||
if (!_Connection.State.HasFlag(ConnectionState.Open))
|
|
||||||
await _Connection.OpenAsync();
|
|
||||||
|
|
||||||
var command = new SqliteCommand(query, _Connection);
|
|
||||||
foreach (var parameter in parameters)
|
|
||||||
{
|
|
||||||
var p = CreateParameter(parameter);
|
|
||||||
if (p is not null)
|
|
||||||
command.Parameters.Add(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
var reader = await command.ExecuteReaderAsync();
|
|
||||||
//
|
|
||||||
if (!reader.HasRows)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
List<T> rows = new();
|
|
||||||
while (await reader.ReadAsync())
|
|
||||||
{
|
|
||||||
var values = new object[reader.FieldCount];
|
|
||||||
reader.GetValues(values);
|
|
||||||
rows.Add(convertor(values));
|
|
||||||
}
|
|
||||||
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<Platforms>AnyCPU;x64;ARM64</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
public interface ILogMessage
|
|
||||||
{
|
|
||||||
public string Message { get; protected set; }
|
|
||||||
public DateTime ThrowTime { get; protected set; }
|
|
||||||
public string SenderName { get; protected set; }
|
|
||||||
public LogType LogMessageType { get; protected set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
namespace DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
public interface ILogger
|
|
||||||
{
|
|
||||||
List<ILogMessage> LogMessages { get; protected set; }
|
|
||||||
event Action<ILogMessage>? OnLogReceived;
|
|
||||||
|
|
||||||
void Log(string message);
|
|
||||||
void Log(string message, LogType logType);
|
|
||||||
void Log(string message, object sender);
|
|
||||||
void Log(string message, object sender, LogType type);
|
|
||||||
void LogException(Exception exception, object sender, bool logFullStack = false);
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
namespace DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
internal sealed class LogMessage : ILogMessage
|
|
||||||
{
|
|
||||||
private static readonly string _DefaultLogMessageSender = "\b";
|
|
||||||
public string Message { get; set; }
|
|
||||||
public DateTime ThrowTime { get; set; }
|
|
||||||
public string SenderName { get; set; }
|
|
||||||
public LogType LogMessageType { get; set; }
|
|
||||||
|
|
||||||
public LogMessage(string message, LogType logMessageType)
|
|
||||||
{
|
|
||||||
Message = message;
|
|
||||||
LogMessageType = logMessageType;
|
|
||||||
ThrowTime = DateTime.Now;
|
|
||||||
SenderName = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogMessage(string message, object sender)
|
|
||||||
{
|
|
||||||
Message = message;
|
|
||||||
SenderName = sender is string && sender as string == string.Empty ? _DefaultLogMessageSender : sender.GetType().FullName ?? sender.GetType().Name;
|
|
||||||
ThrowTime = DateTime.Now;
|
|
||||||
LogMessageType = LogType.Info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogMessage(string message, object sender, DateTime throwTime)
|
|
||||||
{
|
|
||||||
Message = message;
|
|
||||||
SenderName = sender is string && sender as string == string.Empty ? _DefaultLogMessageSender : sender.GetType().FullName ?? sender.GetType().Name;
|
|
||||||
ThrowTime = throwTime;
|
|
||||||
LogMessageType = LogType.Info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogMessage(string message, object sender, LogType logMessageType)
|
|
||||||
{
|
|
||||||
Message = message;
|
|
||||||
SenderName = sender is string && sender as string == string.Empty ? _DefaultLogMessageSender : sender.GetType().FullName ?? sender.GetType().Name;
|
|
||||||
ThrowTime = DateTime.Now;
|
|
||||||
LogMessageType = logMessageType;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogMessage(string message, DateTime throwTime, object sender, LogType logMessageType)
|
|
||||||
{
|
|
||||||
Message = message;
|
|
||||||
ThrowTime = throwTime;
|
|
||||||
SenderName = sender is string && sender as string == string.Empty ? _DefaultLogMessageSender : sender.GetType().FullName ?? sender.GetType().Name;
|
|
||||||
LogMessageType = logMessageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogMessage WithMessage(string message)
|
|
||||||
{
|
|
||||||
this.Message = message;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogMessage WithCurrentThrowTime()
|
|
||||||
{
|
|
||||||
this.ThrowTime = DateTime.Now;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogMessage WithMessageType(LogType logType)
|
|
||||||
{
|
|
||||||
this.LogMessageType = logType;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LogMessage CreateFromException(Exception exception, object Sender, bool logFullStack)
|
|
||||||
{
|
|
||||||
LogMessage message = new LogMessage(logFullStack? exception.ToString() : exception.Message, Sender, LogType.Error);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
public enum LogType
|
|
||||||
{
|
|
||||||
Info,
|
|
||||||
Warning,
|
|
||||||
Error,
|
|
||||||
Critical
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
namespace DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
public sealed class Logger : ILogger
|
|
||||||
{
|
|
||||||
private readonly string _LogFile;
|
|
||||||
private readonly string _LogMessageFormat;
|
|
||||||
private readonly int _MaxHistorySize;
|
|
||||||
|
|
||||||
private readonly List<string> _logMessageProperties = typeof(ILogMessage)
|
|
||||||
.GetProperties()
|
|
||||||
.Select(p => p.Name)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
|
|
||||||
public List<ILogMessage> LogMessages { get; set; }
|
|
||||||
public event Action<ILogMessage>? OnLogReceived;
|
|
||||||
|
|
||||||
|
|
||||||
public Logger(string logFolder, string logMessageFormat, int maxHistorySize)
|
|
||||||
{
|
|
||||||
this._LogMessageFormat = logMessageFormat;
|
|
||||||
this._LogFile = Path.Combine(logFolder, $"{DateTime.Now:yyyy-MM-dd}.log");
|
|
||||||
this._MaxHistorySize = maxHistorySize;
|
|
||||||
LogMessages = new List<ILogMessage>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GenerateLogMessage(ILogMessage message)
|
|
||||||
{
|
|
||||||
string messageAsString = new string(_LogMessageFormat);
|
|
||||||
foreach (var prop in _logMessageProperties)
|
|
||||||
{
|
|
||||||
Type messageType = typeof(ILogMessage);
|
|
||||||
messageAsString = messageAsString.Replace("{" + prop + "}", messageType.GetProperty(prop)?.GetValue(message)?.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return messageAsString;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LogToFile(string message)
|
|
||||||
{
|
|
||||||
await using var streamWriter = new StreamWriter(_LogFile, true);
|
|
||||||
await streamWriter.WriteLineAsync(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Log(ILogMessage message)
|
|
||||||
{
|
|
||||||
var messageAsString = GenerateLogMessage(message);
|
|
||||||
OnLogReceived?.Invoke(message);
|
|
||||||
LogMessages.Add(message);
|
|
||||||
if (LogMessages.Count > _MaxHistorySize)
|
|
||||||
{
|
|
||||||
LogMessages.RemoveAt(0);
|
|
||||||
}
|
|
||||||
await LogToFile(messageAsString);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Log(string message) => Log(new LogMessage(message, string.Empty, LogType.Info));
|
|
||||||
public void Log(string message, LogType logType) => Log(new LogMessage(message, logType));
|
|
||||||
public void Log(string message, object sender) => Log(new LogMessage(message, sender));
|
|
||||||
public void Log(string message, object sender, LogType type) => Log(new LogMessage(message, sender, type));
|
|
||||||
public void LogException(Exception exception, object sender, bool logFullStack = false) => Log(LogMessage.CreateFromException(exception, sender, logFullStack));
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<Platforms>AnyCPU;x64;ARM64</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using DiscordBotCore.Networking.Helpers;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Networking;
|
|
||||||
|
|
||||||
public class FileDownloader
|
|
||||||
{
|
|
||||||
private readonly string _DownloadUrl;
|
|
||||||
private readonly string _DownloadLocation;
|
|
||||||
|
|
||||||
private readonly HttpClient _HttpClient;
|
|
||||||
|
|
||||||
public FileDownloader(string downloadUrl, string downloadLocation)
|
|
||||||
{
|
|
||||||
_DownloadUrl = downloadUrl;
|
|
||||||
_DownloadLocation = downloadLocation;
|
|
||||||
|
|
||||||
_HttpClient = new HttpClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DownloadFile(Action<float> progressCallback)
|
|
||||||
{
|
|
||||||
await using var fileStream = new FileStream(_DownloadLocation, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
||||||
await _HttpClient.DownloadFileAsync(_DownloadUrl, fileStream, new Progress<float>(progressCallback));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
namespace DiscordBotCore.Networking.Helpers;
|
|
||||||
|
|
||||||
internal static class OnlineFunctions
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Copy one Stream to another <see langword="async" />
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">The base stream</param>
|
|
||||||
/// <param name="destination">The destination stream</param>
|
|
||||||
/// <param name="bufferSize">The buffer to read</param>
|
|
||||||
/// <param name="progress">The progress</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token</param>
|
|
||||||
/// <exception cref="ArgumentNullException">Triggered if any <see cref="Stream" /> is empty</exception>
|
|
||||||
/// <exception cref="ArgumentOutOfRangeException">Triggered if <paramref name="bufferSize" /> is less then or equal to 0</exception>
|
|
||||||
/// <exception cref="InvalidOperationException">Triggered if <paramref name="stream" /> is not readable</exception>
|
|
||||||
/// <exception cref="ArgumentException">Triggered in <paramref name="destination" /> is not writable</exception>
|
|
||||||
private static async Task CopyToOtherStreamAsync(
|
|
||||||
this Stream stream, Stream destination, int bufferSize,
|
|
||||||
IProgress<long>? progress = null,
|
|
||||||
CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
if (stream == null) throw new ArgumentNullException(nameof(stream));
|
|
||||||
if (destination == null) throw new ArgumentNullException(nameof(destination));
|
|
||||||
if (bufferSize <= 0) throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
|
||||||
if (!stream.CanRead) throw new InvalidOperationException("The stream is not readable.");
|
|
||||||
if (!destination.CanWrite)
|
|
||||||
throw new ArgumentException("Destination stream is not writable", nameof(destination));
|
|
||||||
|
|
||||||
var buffer = new byte[bufferSize];
|
|
||||||
long totalBytesRead = 0;
|
|
||||||
int bytesRead;
|
|
||||||
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
|
|
||||||
.ConfigureAwait(false)) != 0)
|
|
||||||
{
|
|
||||||
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
|
|
||||||
totalBytesRead += bytesRead;
|
|
||||||
progress?.Report(totalBytesRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Downloads a <see cref="Stream" /> and saves it to another <see cref="Stream" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="client">The <see cref="HttpClient" /> that is used to download the file</param>
|
|
||||||
/// <param name="url">The url to the file</param>
|
|
||||||
/// <param name="destination">The <see cref="Stream" /> to save the downloaded data</param>
|
|
||||||
/// <param name="progress">The <see cref="IProgress{T}" /> that is used to track the download progress</param>
|
|
||||||
/// <param name="cancellation">The cancellation token</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal static async Task DownloadFileAsync(
|
|
||||||
this HttpClient client, string url, Stream destination,
|
|
||||||
IProgress<float>? progress = null,
|
|
||||||
IProgress<long>? downloadedBytes = null, int bufferSize = 81920,
|
|
||||||
CancellationToken cancellation = default)
|
|
||||||
{
|
|
||||||
using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellation))
|
|
||||||
{
|
|
||||||
var contentLength = response.Content.Headers.ContentLength;
|
|
||||||
|
|
||||||
using (var download = await response.Content.ReadAsStreamAsync(cancellation))
|
|
||||||
{
|
|
||||||
// Ignore progress reporting when no progress reporter was
|
|
||||||
// passed or when the content length is unknown
|
|
||||||
if (progress == null || !contentLength.HasValue)
|
|
||||||
{
|
|
||||||
await download.CopyToAsync(destination, cancellation);
|
|
||||||
if (!contentLength.HasValue)
|
|
||||||
progress?.Report(100f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert absolute progress (bytes downloaded) into relative progress (0% - 100%)
|
|
||||||
// total ... 100%
|
|
||||||
// downloaded ... x%
|
|
||||||
// x = downloaded * 100 / total => x = downloaded / total * 100
|
|
||||||
var relativeProgress = new Progress<long>(totalBytesDownloaded =>
|
|
||||||
{
|
|
||||||
progress?.Report(totalBytesDownloaded / (float)contentLength.Value * 100);
|
|
||||||
downloadedBytes?.Report(totalBytesDownloaded);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Use extension method to report progress while downloading
|
|
||||||
await download.CopyToOtherStreamAsync(destination, bufferSize, relativeProgress, cancellation);
|
|
||||||
progress.Report(100f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
using DiscordBotCore.Networking.Helpers;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Networking;
|
|
||||||
|
|
||||||
public class ParallelDownloadExecutor
|
|
||||||
{
|
|
||||||
private readonly List<Task> _listOfTasks;
|
|
||||||
private readonly HttpClient _httpClient;
|
|
||||||
private Action? OnFinishAction { get; set; }
|
|
||||||
|
|
||||||
public ParallelDownloadExecutor(List<Task> listOfTasks)
|
|
||||||
{
|
|
||||||
_httpClient = new HttpClient();
|
|
||||||
_listOfTasks = listOfTasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ParallelDownloadExecutor()
|
|
||||||
{
|
|
||||||
_httpClient = new HttpClient();
|
|
||||||
_listOfTasks = new List<Task>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task StartTasks()
|
|
||||||
{
|
|
||||||
await Task.WhenAll(_listOfTasks);
|
|
||||||
OnFinishAction?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ExecuteAllTasks(int maxDegreeOfParallelism = 4)
|
|
||||||
{
|
|
||||||
using var semaphore = new SemaphoreSlim(maxDegreeOfParallelism);
|
|
||||||
|
|
||||||
var tasks = _listOfTasks.Select(async task =>
|
|
||||||
{
|
|
||||||
await semaphore.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await task;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(tasks);
|
|
||||||
OnFinishAction?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetFinishAction(Action action)
|
|
||||||
{
|
|
||||||
OnFinishAction = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTask(string downloadLink, string downloadLocation)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(downloadLink) || string.IsNullOrEmpty(downloadLocation))
|
|
||||||
throw new ArgumentException("Download link or location cannot be null or empty.");
|
|
||||||
|
|
||||||
if (Directory.Exists(Path.GetDirectoryName(downloadLocation)) == false)
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(downloadLocation));
|
|
||||||
}
|
|
||||||
|
|
||||||
var task = CreateDownloadTask(downloadLink, downloadLocation, null);
|
|
||||||
_listOfTasks.Add(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTask(string downloadLink, string downloadLocation, Action<float> progressCallback)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(downloadLink) || string.IsNullOrEmpty(downloadLocation))
|
|
||||||
throw new ArgumentException("Download link or location cannot be null or empty.");
|
|
||||||
|
|
||||||
if (Directory.Exists(Path.GetDirectoryName(downloadLocation)) == false)
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(downloadLocation));
|
|
||||||
}
|
|
||||||
|
|
||||||
var task = CreateDownloadTask(downloadLink, downloadLocation, new Progress<float>(progressCallback));
|
|
||||||
_listOfTasks.Add(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task CreateDownloadTask(string downloadLink, string downloadLocation, IProgress<float> progress)
|
|
||||||
{
|
|
||||||
var fileStream = new FileStream(downloadLocation, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
||||||
return _httpClient.DownloadFileAsync(downloadLink, fileStream, progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<Platforms>AnyCPU;x64;ARM64</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Discord.Net" Version="3.17.2" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Logging\DiscordBotCore.Logging.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Helpers\Execution\DbSlashCommand\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using Discord.Commands;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginCore.Helpers.Execution.DbCommand;
|
|
||||||
|
|
||||||
public class DbCommandExecutingArgument : IDbCommandExecutingArgument
|
|
||||||
{
|
|
||||||
public SocketCommandContext Context { get; init; }
|
|
||||||
public string CleanContent { get; init; }
|
|
||||||
public string CommandUsed { get; init; }
|
|
||||||
public string[]? Arguments { get; init; }
|
|
||||||
public ILogger Logger { get; init; }
|
|
||||||
public DirectoryInfo PluginBaseDirectory { get; init; }
|
|
||||||
|
|
||||||
public DbCommandExecutingArgument(ILogger logger, SocketCommandContext context, string cleanContent, string commandUsed, string[]? arguments, DirectoryInfo pluginBaseDirectory)
|
|
||||||
{
|
|
||||||
this.Logger = logger;
|
|
||||||
this.Context = context;
|
|
||||||
this.CleanContent = cleanContent;
|
|
||||||
this.CommandUsed = commandUsed;
|
|
||||||
this.Arguments = arguments;
|
|
||||||
this.PluginBaseDirectory = pluginBaseDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using Discord.Commands;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginCore.Helpers.Execution.DbCommand;
|
|
||||||
|
|
||||||
public interface IDbCommandExecutingArgument
|
|
||||||
{
|
|
||||||
ILogger Logger { get; init; }
|
|
||||||
string CleanContent { get; init; }
|
|
||||||
string CommandUsed { get; init; }
|
|
||||||
string[]? Arguments { get; init; }
|
|
||||||
|
|
||||||
SocketCommandContext Context { get; init; }
|
|
||||||
public DirectoryInfo PluginBaseDirectory { get; init; }
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using Discord.WebSocket;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginCore.Helpers.Execution.DbEvent;
|
|
||||||
|
|
||||||
public class DbEventExecutingArgument : IDbEventExecutingArgument
|
|
||||||
{
|
|
||||||
public ILogger Logger { get; }
|
|
||||||
public DiscordSocketClient Client { get; }
|
|
||||||
public string BotPrefix { get; }
|
|
||||||
public DirectoryInfo PluginBaseDirectory { get; }
|
|
||||||
|
|
||||||
public DbEventExecutingArgument(ILogger logger, DiscordSocketClient client, string botPrefix, DirectoryInfo pluginBaseDirectory)
|
|
||||||
{
|
|
||||||
Logger = logger;
|
|
||||||
Client = client;
|
|
||||||
BotPrefix = botPrefix;
|
|
||||||
PluginBaseDirectory = pluginBaseDirectory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using Discord.WebSocket;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginCore.Helpers.Execution.DbEvent;
|
|
||||||
|
|
||||||
public interface IDbEventExecutingArgument
|
|
||||||
{
|
|
||||||
public ILogger Logger { get; }
|
|
||||||
public DiscordSocketClient Client { get; }
|
|
||||||
public string BotPrefix { get; }
|
|
||||||
public DirectoryInfo PluginBaseDirectory { get; }
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
using DiscordBotCore.PluginCore.Helpers.Execution.DbCommand;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginCore.Interfaces;
|
|
||||||
|
|
||||||
public interface IDbCommand
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Command to be executed
|
|
||||||
/// It's CaSe SeNsItIvE
|
|
||||||
/// </summary>
|
|
||||||
string Command { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Command aliases. Users may use this to execute the command
|
|
||||||
/// </summary>
|
|
||||||
List<string> Aliases { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Command description
|
|
||||||
/// </summary>
|
|
||||||
string Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The usage for your command.
|
|
||||||
/// It will be displayed when users type help
|
|
||||||
/// </summary>
|
|
||||||
string Usage { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// true if the command requre admin, otherwise false
|
|
||||||
/// </summary>
|
|
||||||
bool RequireAdmin { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The main body of the command. This is what is executed when user calls the command in Server
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">The Discord Context</param>
|
|
||||||
Task ExecuteServer(IDbCommandExecutingArgument args) => Task.CompletedTask;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The main body of the command. This is what is executed when user calls the command in DM
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">The Discord Context</param>
|
|
||||||
Task ExecuteDm(IDbCommandExecutingArgument args) => Task.CompletedTask;
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using DiscordBotCore.PluginCore.Helpers.Execution.DbEvent;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginCore.Interfaces;
|
|
||||||
|
|
||||||
public interface IDbEvent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the event
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The description of the event
|
|
||||||
/// </summary>
|
|
||||||
string Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The method that is invoked when the event is loaded into memory
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">The arguments for the start method</param>
|
|
||||||
void Start(IDbEventExecutingArgument args);
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using Discord;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginCore.Interfaces;
|
|
||||||
|
|
||||||
public interface IDbSlashCommand
|
|
||||||
{
|
|
||||||
string Name { get; }
|
|
||||||
string Description { get; }
|
|
||||||
bool CanUseDm { get; }
|
|
||||||
bool HasInteraction { get; }
|
|
||||||
|
|
||||||
List<SlashCommandOptionBuilder> Options { get; }
|
|
||||||
|
|
||||||
void ExecuteServer(ILogger logger, SocketSlashCommand context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void ExecuteDm(ILogger logger, SocketSlashCommand context) { }
|
|
||||||
|
|
||||||
Task ExecuteInteraction(ILogger logger, SocketInteraction interaction) => Task.CompletedTask;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<Platforms>AnyCPU;x64;ARM64</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Configuration\DiscordBotCore.Configuration.csproj" />
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Logging\DiscordBotCore.Logging.csproj" />
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.PluginCore\DiscordBotCore.PluginCore.csproj" />
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.PluginManagement\DiscordBotCore.PluginManagement.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace DiscordBotCore.PluginManagement.Loading.Exceptions;
|
|
||||||
|
|
||||||
public class PluginNotFoundException : Exception
|
|
||||||
{
|
|
||||||
public PluginNotFoundException(string pluginName) : base($"Plugin {pluginName} was not found") { }
|
|
||||||
|
|
||||||
public PluginNotFoundException(string pluginName, string url, string branch) :
|
|
||||||
base ($"Plugin {pluginName} was not found on {url} (branch: {branch}") { }
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
using Discord.WebSocket;
|
|
||||||
using DiscordBotCore.PluginCore.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement.Loading;
|
|
||||||
|
|
||||||
public interface IPluginLoader
|
|
||||||
{
|
|
||||||
public IReadOnlyList<IDbCommand> Commands { get; }
|
|
||||||
public IReadOnlyList<IDbEvent> Events { get; }
|
|
||||||
public IReadOnlyList<IDbSlashCommand> SlashCommands { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the Discord client for the plugin loader. This is used to initialize the slash commands and events.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="discordSocketClient">The socket client that represents the running Discord Bot</param>
|
|
||||||
public void SetDiscordClient(DiscordSocketClient discordSocketClient);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads all the plugins that are installed.
|
|
||||||
/// </summary>
|
|
||||||
public Task LoadPlugins();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unload all plugins from the plugin manager.
|
|
||||||
/// </summary>
|
|
||||||
public Task UnloadAllPlugins();
|
|
||||||
}
|
|
||||||
@@ -1,371 +0,0 @@
|
|||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Reflection;
|
|
||||||
using Discord;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using DiscordBotCore.Configuration;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
using DiscordBotCore.PluginCore.Helpers.Execution.DbEvent;
|
|
||||||
using DiscordBotCore.PluginCore.Interfaces;
|
|
||||||
using DiscordBotCore.PluginManagement.Loading.Exceptions;
|
|
||||||
using DiscordBotCore.Utilities.Responses;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement.Loading;
|
|
||||||
|
|
||||||
public class PluginLoader : IPluginLoader
|
|
||||||
{
|
|
||||||
private static readonly string _HelpCommandNamespaceFullName = "DiscordBotCore.Commands.HelpCommand";
|
|
||||||
|
|
||||||
private readonly IPluginManager _PluginManager;
|
|
||||||
private readonly ILogger _Logger;
|
|
||||||
private readonly IConfiguration _Configuration;
|
|
||||||
|
|
||||||
private DiscordSocketClient? _DiscordClient;
|
|
||||||
private PluginLoaderContext? PluginLoaderContext;
|
|
||||||
|
|
||||||
private readonly List<IDbCommand> _Commands = new List<IDbCommand>();
|
|
||||||
private readonly List<IDbEvent> _Events = new List<IDbEvent>();
|
|
||||||
private readonly List<IDbSlashCommand> _SlashCommands = new List<IDbSlashCommand>();
|
|
||||||
private readonly List<SocketApplicationCommand> _ApplicationCommands = new List<SocketApplicationCommand>();
|
|
||||||
|
|
||||||
public PluginLoader(IPluginManager pluginManager, ILogger logger, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
_PluginManager = pluginManager;
|
|
||||||
_Logger = logger;
|
|
||||||
_Configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IReadOnlyList<IDbCommand> Commands => _Commands;
|
|
||||||
public IReadOnlyList<IDbEvent> Events => _Events;
|
|
||||||
public IReadOnlyList<IDbSlashCommand> SlashCommands => _SlashCommands;
|
|
||||||
|
|
||||||
public void SetDiscordClient(DiscordSocketClient discordSocketClient)
|
|
||||||
{
|
|
||||||
if (_DiscordClient is not null && discordSocketClient == _DiscordClient)
|
|
||||||
{
|
|
||||||
_Logger.Log("A client is already set. Please set the client only once.", this, LogType.Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (discordSocketClient.LoginState != LoginState.LoggedIn)
|
|
||||||
{
|
|
||||||
_Logger.Log("The client must be logged in before setting it.", this, LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_DiscordClient = discordSocketClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task LoadPlugins()
|
|
||||||
{
|
|
||||||
if (PluginLoaderContext is not null)
|
|
||||||
{
|
|
||||||
_Logger.Log("The plugins are already loaded", this, LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Events.Clear();
|
|
||||||
_Commands.Clear();
|
|
||||||
_SlashCommands.Clear();
|
|
||||||
_ApplicationCommands.Clear();
|
|
||||||
|
|
||||||
await LoadPluginFiles();
|
|
||||||
|
|
||||||
LoadEverythingOfType<IDbEvent>();
|
|
||||||
var helpCommand = AppDomain.CurrentDomain.GetAssemblies()
|
|
||||||
.FirstOrDefault(assembly => assembly.DefinedTypes.Any(type => type.FullName == _HelpCommandNamespaceFullName)
|
|
||||||
&& assembly.FullName != null
|
|
||||||
&& assembly.FullName.StartsWith("DiscordBotCore"));
|
|
||||||
|
|
||||||
if (helpCommand is not null)
|
|
||||||
{
|
|
||||||
var helpCommandType = helpCommand.DefinedTypes.FirstOrDefault(type => type.FullName == _HelpCommandNamespaceFullName &&
|
|
||||||
typeof(IDbCommand).IsAssignableFrom(type));
|
|
||||||
if (helpCommandType is not null)
|
|
||||||
{
|
|
||||||
InitializeType<IDbCommand>(helpCommandType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadEverythingOfType<IDbCommand>();
|
|
||||||
LoadEverythingOfType<IDbSlashCommand>();
|
|
||||||
|
|
||||||
|
|
||||||
_Logger.Log("Loaded plugins", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UnloadAllPlugins()
|
|
||||||
{
|
|
||||||
if (PluginLoaderContext is null)
|
|
||||||
{
|
|
||||||
_Logger.Log("The plugins are not loaded. Please load the plugins before unloading them.", this, LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await UnloadSlashCommands();
|
|
||||||
|
|
||||||
PluginLoaderContext.Unload();
|
|
||||||
PluginLoaderContext = null;
|
|
||||||
|
|
||||||
GC.Collect();
|
|
||||||
GC.WaitForPendingFinalizers();
|
|
||||||
GC.Collect();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UnloadSlashCommands()
|
|
||||||
{
|
|
||||||
if (_DiscordClient is null)
|
|
||||||
{
|
|
||||||
_Logger.Log("The client is not set. Please set the client before unloading slash commands.", this, LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (SocketApplicationCommand command in _ApplicationCommands)
|
|
||||||
{
|
|
||||||
await command.DeleteAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
_ApplicationCommands.Clear();
|
|
||||||
_Logger.Log("Unloaded all slash commands", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LoadPluginFiles()
|
|
||||||
{
|
|
||||||
var installedPlugins = await _PluginManager.GetInstalledPlugins();
|
|
||||||
|
|
||||||
if (installedPlugins.Count == 0)
|
|
||||||
{
|
|
||||||
_Logger.Log("No plugin files found. Please check the plugin files.", this, LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var files = installedPlugins.Where(plugin => plugin.IsEnabled).Select(plugin => plugin.FilePath);
|
|
||||||
|
|
||||||
PluginLoaderContext = new PluginLoaderContext(_Logger, "PluginLoader");
|
|
||||||
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
string fullFilePath = Path.GetFullPath(file);
|
|
||||||
if (string.IsNullOrEmpty(fullFilePath))
|
|
||||||
{
|
|
||||||
_Logger.Log("The file path is empty. Please check the plugin file path.", PluginLoaderContext, LogType.Error);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!File.Exists(fullFilePath))
|
|
||||||
{
|
|
||||||
_Logger.Log("The file does not exist. Please check the plugin file path.", PluginLoaderContext, LogType.Error);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PluginLoaderContext.LoadFromAssemblyPath(fullFilePath);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_Logger.LogException(ex, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_Logger.Log($"Loaded {PluginLoaderContext.Assemblies.Count()} assemblies", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadEverythingOfType<T>()
|
|
||||||
{
|
|
||||||
if (PluginLoaderContext is null)
|
|
||||||
{
|
|
||||||
_Logger.Log("The plugins are not loaded. Please load the plugins before loading them.", this, LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var types = PluginLoaderContext.Assemblies
|
|
||||||
.SelectMany(s => s.GetTypes())
|
|
||||||
.Where(p => typeof(T).IsAssignableFrom(p) && !p.IsInterface);
|
|
||||||
|
|
||||||
foreach (var type in types)
|
|
||||||
{
|
|
||||||
InitializeType<T>(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeType<T>(Type type)
|
|
||||||
{
|
|
||||||
T? plugin = (T?)Activator.CreateInstance(type);
|
|
||||||
if (plugin is null)
|
|
||||||
{
|
|
||||||
_Logger.Log($"Failed to create instance of plugin with type {type.FullName} [{type.Assembly}]", this, LogType.Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (plugin)
|
|
||||||
{
|
|
||||||
case IDbEvent dbEvent:
|
|
||||||
InitializeEvent(dbEvent);
|
|
||||||
break;
|
|
||||||
case IDbCommand dbCommand:
|
|
||||||
InitializeDbCommand(dbCommand);
|
|
||||||
break;
|
|
||||||
case IDbSlashCommand dbSlashCommand:
|
|
||||||
InitializeSlashCommand(dbSlashCommand);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new PluginNotFoundException($"Unknown plugin type {plugin.GetType().FullName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeDbCommand(IDbCommand command)
|
|
||||||
{
|
|
||||||
_Commands.Add(command);
|
|
||||||
_Logger.Log("Command loaded: " + command.Command, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeEvent(IDbEvent eEvent)
|
|
||||||
{
|
|
||||||
if (!TryStartEvent(eEvent))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Events.Add(eEvent);
|
|
||||||
_Logger.Log("Event loaded: " + eEvent, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void InitializeSlashCommand(IDbSlashCommand slashCommand)
|
|
||||||
{
|
|
||||||
bool result = await TryStartSlashCommand(slashCommand);
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_DiscordClient is null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slashCommand.HasInteraction)
|
|
||||||
{
|
|
||||||
_DiscordClient.InteractionCreated += interaction => slashCommand.ExecuteInteraction(_Logger, interaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
_SlashCommands.Add(slashCommand);
|
|
||||||
_Logger.Log("Slash command loaded: " + slashCommand.Name, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryStartEvent(IDbEvent dbEvent)
|
|
||||||
{
|
|
||||||
string? botPrefix = _Configuration.Get<string>("prefix");
|
|
||||||
if (string.IsNullOrEmpty(botPrefix))
|
|
||||||
{
|
|
||||||
_Logger.Log("Bot prefix is not set. Please set the bot prefix in the configuration.", this, LogType.Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_DiscordClient is null)
|
|
||||||
{
|
|
||||||
_Logger.Log("Discord client is not set. Please set the discord client before starting events.", this, LogType.Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string? resourcesFolder = _Configuration.Get<string>("ResourcesFolder");
|
|
||||||
if (string.IsNullOrEmpty(resourcesFolder))
|
|
||||||
{
|
|
||||||
_Logger.Log("Resources folder is not set. Please set the resources folder in the configuration.", this, LogType.Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(resourcesFolder))
|
|
||||||
{
|
|
||||||
_Logger.Log("Resources folder does not exist. Please create the resources folder.", this, LogType.Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string? eventConfigDirectory = Path.Combine(resourcesFolder, dbEvent.GetType().Assembly.GetName().Name);
|
|
||||||
|
|
||||||
Directory.CreateDirectory(eventConfigDirectory);
|
|
||||||
|
|
||||||
IDbEventExecutingArgument args = new DbEventExecutingArgument(
|
|
||||||
_Logger,
|
|
||||||
_DiscordClient,
|
|
||||||
botPrefix,
|
|
||||||
new DirectoryInfo(eventConfigDirectory));
|
|
||||||
|
|
||||||
dbEvent.Start(args);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> TryStartSlashCommand(IDbSlashCommand? dbSlashCommand)
|
|
||||||
{
|
|
||||||
if (dbSlashCommand is null)
|
|
||||||
{
|
|
||||||
_Logger.Log("The loaded slash command was null. Please check the plugin.", this, LogType.Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_DiscordClient is null)
|
|
||||||
{
|
|
||||||
_Logger.Log("The client is not set. Please set the client before starting slash commands.", this, LogType.Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_DiscordClient.Guilds.Count == 0)
|
|
||||||
{
|
|
||||||
_Logger.Log("The client is not connected to any guilds. Please check the client.", this, LogType.Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var builder = new SlashCommandBuilder();
|
|
||||||
builder.WithName(dbSlashCommand.Name);
|
|
||||||
builder.WithDescription(dbSlashCommand.Description);
|
|
||||||
builder.Options = dbSlashCommand.Options;
|
|
||||||
|
|
||||||
if (dbSlashCommand.CanUseDm)
|
|
||||||
builder.WithContextTypes(InteractionContextType.BotDm, InteractionContextType.Guild);
|
|
||||||
else
|
|
||||||
builder.WithContextTypes(InteractionContextType.Guild);
|
|
||||||
|
|
||||||
List<ulong> serverIds = _Configuration.GetList("ServerIds", new List<ulong>());
|
|
||||||
|
|
||||||
if (serverIds.Any())
|
|
||||||
{
|
|
||||||
foreach(ulong guildId in serverIds)
|
|
||||||
{
|
|
||||||
IResponse<SocketApplicationCommand> result = await EnableSlashCommandPerGuild(guildId, builder);
|
|
||||||
|
|
||||||
if (!result.IsSuccess)
|
|
||||||
{
|
|
||||||
_Logger.Log($"Failed to enable slash command {dbSlashCommand.Name} for guild {guildId}", this, LogType.Error);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.Data is null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ApplicationCommands.Add(result.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var command = await _DiscordClient.CreateGlobalApplicationCommandAsync(builder.Build());
|
|
||||||
_ApplicationCommands.Add(command);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IResponse<SocketApplicationCommand>> EnableSlashCommandPerGuild(ulong guildId, SlashCommandBuilder builder)
|
|
||||||
{
|
|
||||||
SocketGuild? guild = _DiscordClient?.GetGuild(guildId);
|
|
||||||
if (guild is null)
|
|
||||||
{
|
|
||||||
_Logger.Log("Failed to get guild with ID " + guildId, this, LogType.Error);
|
|
||||||
return Response<SocketApplicationCommand>.Failure("Failed to get guild with ID " + guildId);
|
|
||||||
}
|
|
||||||
|
|
||||||
var command = await guild.CreateApplicationCommandAsync(builder.Build());
|
|
||||||
return Response<SocketApplicationCommand>.Success(command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.Loader;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement.Loading;
|
|
||||||
|
|
||||||
public class PluginLoaderContext : AssemblyLoadContext
|
|
||||||
{
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public PluginLoaderContext(ILogger logger, string name) : base(name: name, isCollectible: true)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Assembly? Load(AssemblyName assemblyName)
|
|
||||||
{
|
|
||||||
//_logger.Log("Assembly load requested: " + assemblyName.Name, this);
|
|
||||||
return base.Load(assemblyName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<Platforms>AnyCPU;x64;ARM64</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.3.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Configuration\DiscordBotCore.Configuration.csproj" />
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Logging\DiscordBotCore.Logging.csproj" />
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Networking\DiscordBotCore.Networking.csproj" />
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Utilities\DiscordBotCore.Utilities.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using DiscordBotCore.PluginManagement.Models;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement.Helpers;
|
|
||||||
|
|
||||||
public interface IPluginRepository
|
|
||||||
{
|
|
||||||
public Task<List<OnlinePlugin>> GetAllPlugins(int operatingSystem, bool includeNotApproved);
|
|
||||||
|
|
||||||
public Task<OnlinePlugin?> GetPluginById(int pluginId);
|
|
||||||
public Task<OnlinePlugin?> GetPluginByName(string pluginName, int operatingSystem, bool includeNotApproved);
|
|
||||||
|
|
||||||
public Task<List<OnlineDependencyInfo>> GetDependenciesForPlugin(int pluginId);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace DiscordBotCore.PluginManagement.Helpers;
|
|
||||||
|
|
||||||
public interface IPluginRepositoryConfiguration
|
|
||||||
{
|
|
||||||
public string BaseUrl { get; }
|
|
||||||
|
|
||||||
public string PluginRepositoryLocation { get; }
|
|
||||||
public string DependenciesRepositoryLocation { get; }
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
using System.Net.Mime;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
using DiscordBotCore.PluginManagement.Models;
|
|
||||||
using DiscordBotCore.Utilities;
|
|
||||||
using Microsoft.AspNetCore.Http.Extensions;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement.Helpers;
|
|
||||||
|
|
||||||
public class PluginRepository : IPluginRepository
|
|
||||||
{
|
|
||||||
private readonly IPluginRepositoryConfiguration _pluginRepositoryConfiguration;
|
|
||||||
private readonly HttpClient _httpClient;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public PluginRepository(IPluginRepositoryConfiguration pluginRepositoryConfiguration, ILogger logger)
|
|
||||||
{
|
|
||||||
_pluginRepositoryConfiguration = pluginRepositoryConfiguration;
|
|
||||||
_httpClient = new HttpClient();
|
|
||||||
_httpClient.BaseAddress = new Uri(_pluginRepositoryConfiguration.BaseUrl);
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<OnlinePlugin>> GetAllPlugins(int operatingSystem, bool includeNotApproved)
|
|
||||||
{
|
|
||||||
string url = CreateUrlWithQueryParams(_pluginRepositoryConfiguration.PluginRepositoryLocation,
|
|
||||||
"get-all-plugins", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "operatingSystem", operatingSystem.ToString() },
|
|
||||||
{ "includeNotApproved", includeNotApproved.ToString() }
|
|
||||||
});
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HttpResponseMessage response = await _httpClient.GetAsync(url);
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
string content = await response.Content.ReadAsStringAsync();
|
|
||||||
List<OnlinePlugin> plugins = await JsonManager.ConvertFromJson<List<OnlinePlugin>>(content);
|
|
||||||
|
|
||||||
return plugins;
|
|
||||||
}
|
|
||||||
catch (HttpRequestException exception)
|
|
||||||
{
|
|
||||||
_logger.LogException(exception,this);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<OnlinePlugin?> GetPluginById(int pluginId)
|
|
||||||
{
|
|
||||||
string url = CreateUrlWithQueryParams(_pluginRepositoryConfiguration.PluginRepositoryLocation,
|
|
||||||
"get-by-id", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "pluginId", pluginId.ToString() },
|
|
||||||
{ "includeNotApproved", "false" }
|
|
||||||
});
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HttpResponseMessage response = await _httpClient.GetAsync(url);
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string content = await response.Content.ReadAsStringAsync();
|
|
||||||
OnlinePlugin plugin = await JsonManager.ConvertFromJson<OnlinePlugin>(content);
|
|
||||||
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
catch (HttpRequestException exception)
|
|
||||||
{
|
|
||||||
_logger.LogException(exception, this);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<OnlinePlugin?> GetPluginByName(string pluginName, int operatingSystem, bool includeNotApproved)
|
|
||||||
{
|
|
||||||
string url = CreateUrlWithQueryParams(_pluginRepositoryConfiguration.PluginRepositoryLocation,
|
|
||||||
"get-by-name", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "pluginName", pluginName },
|
|
||||||
{ "operatingSystem", operatingSystem.ToString() },
|
|
||||||
{ "includeNotApproved", includeNotApproved.ToString() }
|
|
||||||
});
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HttpResponseMessage response = await _httpClient.GetAsync(url);
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
_logger.Log($"Plugin {pluginName} not found");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string content = await response.Content.ReadAsStringAsync();
|
|
||||||
OnlinePlugin plugin = await JsonManager.ConvertFromJson<OnlinePlugin>(content);
|
|
||||||
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
catch (HttpRequestException exception)
|
|
||||||
{
|
|
||||||
_logger.LogException(exception, this);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<OnlineDependencyInfo>> GetDependenciesForPlugin(int pluginId)
|
|
||||||
{
|
|
||||||
string url = CreateUrlWithQueryParams(_pluginRepositoryConfiguration.DependenciesRepositoryLocation,
|
|
||||||
"get-by-plugin-id", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "pluginId", pluginId.ToString() }
|
|
||||||
});
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HttpResponseMessage response = await _httpClient.GetAsync(url);
|
|
||||||
if(!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
_logger.Log($"Failed to get dependencies for plugin with ID {pluginId}");
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
string content = await response.Content.ReadAsStringAsync();
|
|
||||||
List<OnlineDependencyInfo> dependencies = await JsonManager.ConvertFromJson<List<OnlineDependencyInfo>>(content);
|
|
||||||
|
|
||||||
return dependencies;
|
|
||||||
}
|
|
||||||
catch(HttpRequestException exception)
|
|
||||||
{
|
|
||||||
_logger.LogException(exception, this);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private string CreateUrlWithQueryParams(string baseUrl, string endpoint, Dictionary<string, string> queryParams)
|
|
||||||
{
|
|
||||||
QueryBuilder queryBuilder = new QueryBuilder();
|
|
||||||
foreach (var(key,value) in queryParams)
|
|
||||||
{
|
|
||||||
queryBuilder.Add(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
string queryString = queryBuilder.ToQueryString().ToString();
|
|
||||||
string url = baseUrl + endpoint + queryString;
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement.Helpers;
|
|
||||||
|
|
||||||
public class PluginRepositoryConfiguration : IPluginRepositoryConfiguration
|
|
||||||
{
|
|
||||||
public static PluginRepositoryConfiguration Default => new ("http://localhost:8080/api/v1/",
|
|
||||||
"plugin/",
|
|
||||||
"dependency/");
|
|
||||||
|
|
||||||
public string BaseUrl { get; }
|
|
||||||
public string PluginRepositoryLocation { get; }
|
|
||||||
public string DependenciesRepositoryLocation { get; }
|
|
||||||
|
|
||||||
[JsonConstructor]
|
|
||||||
public PluginRepositoryConfiguration(string baseUrl, string pluginRepositoryLocation, string dependenciesRepositoryLocation)
|
|
||||||
{
|
|
||||||
BaseUrl = baseUrl;
|
|
||||||
PluginRepositoryLocation = pluginRepositoryLocation;
|
|
||||||
DependenciesRepositoryLocation = dependenciesRepositoryLocation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using DiscordBotCore.PluginManagement.Models;
|
|
||||||
using DiscordBotCore.Utilities.Responses;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement;
|
|
||||||
|
|
||||||
public interface IPluginManager
|
|
||||||
{
|
|
||||||
Task<List<OnlinePlugin>> GetPluginsList();
|
|
||||||
Task<IResponse<OnlinePlugin>> GetPluginDataByName(string pluginName);
|
|
||||||
Task<IResponse<OnlinePlugin>> GetPluginDataById(int pluginId);
|
|
||||||
Task<IResponse<bool>> AppendPluginToDatabase(LocalPlugin pluginData);
|
|
||||||
Task<List<LocalPlugin>> GetInstalledPlugins();
|
|
||||||
Task<IResponse<string>> GetDependencyLocation(string dependencyName);
|
|
||||||
Task<IResponse<string>> GetDependencyLocation(string dependencyName, string pluginName);
|
|
||||||
string GenerateDependencyRelativePath(string pluginName, string dependencyPath);
|
|
||||||
Task<IResponse<bool>> InstallPlugin(OnlinePlugin plugin, IProgress<float> progress);
|
|
||||||
Task SetEnabledStatus(string pluginName, bool status);
|
|
||||||
Task<IResponse<bool>> UninstallPluginByName(string pluginName);
|
|
||||||
Task<IResponse<LocalPlugin>> GetLocalPluginByName(string pluginName);
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement.Models;
|
|
||||||
|
|
||||||
public class LocalPlugin
|
|
||||||
{
|
|
||||||
public string PluginName { get; private set; }
|
|
||||||
public string PluginVersion { get; private set; }
|
|
||||||
public string FilePath { get; private set; }
|
|
||||||
public Dictionary<string, string> ListOfExecutableDependencies {get; private set;}
|
|
||||||
public bool IsOfflineAdded { get; internal set; }
|
|
||||||
public bool IsEnabled { get; internal set; }
|
|
||||||
|
|
||||||
[JsonConstructor]
|
|
||||||
public LocalPlugin(string pluginName, string pluginVersion, string filePath, Dictionary<string, string> listOfExecutableDependencies, bool isOfflineAdded, bool isEnabled)
|
|
||||||
{
|
|
||||||
PluginName = pluginName;
|
|
||||||
PluginVersion = pluginVersion;
|
|
||||||
ListOfExecutableDependencies = listOfExecutableDependencies;
|
|
||||||
FilePath = filePath;
|
|
||||||
IsOfflineAdded = isOfflineAdded;
|
|
||||||
IsEnabled = isEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LocalPlugin(string pluginName, string pluginVersion, string filePath,
|
|
||||||
Dictionary<string, string> listOfExecutableDependencies)
|
|
||||||
{
|
|
||||||
PluginName = pluginName;
|
|
||||||
PluginVersion = pluginVersion;
|
|
||||||
ListOfExecutableDependencies = listOfExecutableDependencies;
|
|
||||||
FilePath = filePath;
|
|
||||||
IsOfflineAdded = false;
|
|
||||||
IsEnabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LocalPlugin FromOnlineInfo(OnlinePlugin plugin, List<OnlineDependencyInfo> dependencies, string downloadLocation)
|
|
||||||
{
|
|
||||||
LocalPlugin localPlugin = new LocalPlugin(
|
|
||||||
plugin.Name, plugin.Version, downloadLocation,
|
|
||||||
dependencies.Where(dependency => dependency.IsExecutable)
|
|
||||||
.ToDictionary(dependency => dependency.DependencyName, dependency => dependency.DownloadLocation)
|
|
||||||
);
|
|
||||||
|
|
||||||
return localPlugin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement.Models;
|
|
||||||
|
|
||||||
public class OnlineDependencyInfo
|
|
||||||
{
|
|
||||||
public string DependencyName { get; private set; }
|
|
||||||
[JsonPropertyName("dependencyLink")]
|
|
||||||
public string DownloadLink { get; private set; }
|
|
||||||
[JsonPropertyName("dependencyLocation")]
|
|
||||||
public string DownloadLocation { get; private set; }
|
|
||||||
public bool IsExecutable { get; private set; }
|
|
||||||
|
|
||||||
[JsonConstructor]
|
|
||||||
public OnlineDependencyInfo(string dependencyName, string downloadLink, string downloadLocation, bool isExecutable)
|
|
||||||
{
|
|
||||||
DependencyName = dependencyName;
|
|
||||||
DownloadLink = downloadLink;
|
|
||||||
DownloadLocation = downloadLocation;
|
|
||||||
IsExecutable = isExecutable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement.Models;
|
|
||||||
|
|
||||||
public class OnlinePlugin
|
|
||||||
{
|
|
||||||
public int Id { get; private set; }
|
|
||||||
public string Name { get; private set; }
|
|
||||||
public string Description { get; private set; }
|
|
||||||
public string Version { get; private set; }
|
|
||||||
public string Author { get; private set; }
|
|
||||||
public string DownloadLink { get; private set; }
|
|
||||||
public int OperatingSystem { get; private set; }
|
|
||||||
public bool IsApproved { get; private set; }
|
|
||||||
|
|
||||||
[JsonConstructor]
|
|
||||||
public OnlinePlugin(int id, string name, string description, string version,
|
|
||||||
string author, string downloadLink, int operatingSystem, bool isApproved)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
Name = name;
|
|
||||||
Description = description;
|
|
||||||
Version = version;
|
|
||||||
Author = author;
|
|
||||||
DownloadLink = downloadLink;
|
|
||||||
OperatingSystem = operatingSystem;
|
|
||||||
IsApproved = isApproved;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,316 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
using DiscordBotCore.Networking;
|
|
||||||
using DiscordBotCore.PluginManagement.Helpers;
|
|
||||||
using DiscordBotCore.PluginManagement.Models;
|
|
||||||
using DiscordBotCore.Utilities;
|
|
||||||
using DiscordBotCore.Configuration;
|
|
||||||
using DiscordBotCore.Utilities.Responses;
|
|
||||||
using OperatingSystem = DiscordBotCore.Utilities.OperatingSystem;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.PluginManagement;
|
|
||||||
|
|
||||||
public sealed class PluginManager : IPluginManager
|
|
||||||
{
|
|
||||||
private static readonly string _LibrariesBaseFolder = "Libraries";
|
|
||||||
private readonly IPluginRepository _PluginRepository;
|
|
||||||
private readonly ILogger _Logger;
|
|
||||||
private readonly IConfiguration _Configuration;
|
|
||||||
|
|
||||||
public PluginManager(IPluginRepository pluginRepository, ILogger logger, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
_PluginRepository = pluginRepository;
|
|
||||||
_Logger = logger;
|
|
||||||
_Configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<OnlinePlugin>> GetPluginsList()
|
|
||||||
{
|
|
||||||
int os = OperatingSystem.GetOperatingSystemInt();
|
|
||||||
var onlinePlugins = await _PluginRepository.GetAllPlugins(os, false);
|
|
||||||
|
|
||||||
if (!onlinePlugins.Any())
|
|
||||||
{
|
|
||||||
_Logger.Log($"No plugins found for operatingSystem: {OperatingSystem.GetOperatingSystemString((OperatingSystem.OperatingSystemEnum)os)}", LogType.Warning);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return onlinePlugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IResponse<OnlinePlugin>> GetPluginDataByName(string pluginName)
|
|
||||||
{
|
|
||||||
int os = OperatingSystem.GetOperatingSystemInt();
|
|
||||||
var plugin = await _PluginRepository.GetPluginByName(pluginName, os, false);
|
|
||||||
|
|
||||||
if (plugin is null)
|
|
||||||
{
|
|
||||||
return Response<OnlinePlugin>.Failure($"Plugin {pluginName} not found in the repository for operating system {OperatingSystem.GetOperatingSystemString((OperatingSystem.OperatingSystemEnum)os)}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response<OnlinePlugin>.Success(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IResponse<OnlinePlugin>> GetPluginDataById(int pluginId)
|
|
||||||
{
|
|
||||||
var plugin = await _PluginRepository.GetPluginById(pluginId);
|
|
||||||
if (plugin is null)
|
|
||||||
{
|
|
||||||
return Response<OnlinePlugin>.Failure($"Plugin {pluginId} not found in the repository.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response<OnlinePlugin>.Success(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IResponse<bool>> RemovePluginFromDatabase(string pluginName)
|
|
||||||
{
|
|
||||||
string? pluginDatabaseFile = _Configuration.Get<string>("PluginDatabase");
|
|
||||||
|
|
||||||
if (pluginDatabaseFile is null)
|
|
||||||
{
|
|
||||||
return Response.Failure("PluginDatabase file path is not present in the config file");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<LocalPlugin> installedPlugins = await JsonManager.ConvertFromJson<List<LocalPlugin>>(await File.ReadAllTextAsync(pluginDatabaseFile));
|
|
||||||
|
|
||||||
installedPlugins.RemoveAll(p => p.PluginName == pluginName);
|
|
||||||
await JsonManager.SaveToJsonFile(pluginDatabaseFile, installedPlugins);
|
|
||||||
|
|
||||||
return Response.Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IResponse<bool>> AppendPluginToDatabase(LocalPlugin pluginData)
|
|
||||||
{
|
|
||||||
string? pluginDatabaseFile = _Configuration.Get<string>("PluginDatabase");
|
|
||||||
if (pluginDatabaseFile is null)
|
|
||||||
{
|
|
||||||
return Response.Failure("PluginDatabase file path is not present in the config file");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<LocalPlugin> installedPlugins = await GetInstalledPlugins();
|
|
||||||
|
|
||||||
foreach (var dependency in pluginData.ListOfExecutableDependencies)
|
|
||||||
{
|
|
||||||
pluginData.ListOfExecutableDependencies[dependency.Key] = dependency.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (installedPlugins.Any(plugin => plugin.PluginName == pluginData.PluginName))
|
|
||||||
{
|
|
||||||
_Logger.Log($"Plugin {pluginData.PluginName} already exists in the database. Updating...", this, LogType.Info);
|
|
||||||
installedPlugins.RemoveAll(p => p.PluginName == pluginData.PluginName);
|
|
||||||
}
|
|
||||||
|
|
||||||
installedPlugins.Add(pluginData);
|
|
||||||
await JsonManager.SaveToJsonFile(pluginDatabaseFile, installedPlugins);
|
|
||||||
|
|
||||||
return Response.Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<LocalPlugin>> GetInstalledPlugins()
|
|
||||||
{
|
|
||||||
string? pluginDatabaseFile = _Configuration.Get<string>("PluginDatabase");
|
|
||||||
if (pluginDatabaseFile is null)
|
|
||||||
{
|
|
||||||
_Logger.Log("Plugin database file path is not present in the config file", this, LogType.Warning);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!File.Exists(pluginDatabaseFile))
|
|
||||||
{
|
|
||||||
_Logger.Log("Plugin database file not found", this, LogType.Warning);
|
|
||||||
await CreateEmptyPluginDatabase();
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return await JsonManager.ConvertFromJson<List<LocalPlugin>>(await File.ReadAllTextAsync(pluginDatabaseFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IResponse<string>> GetDependencyLocation(string dependencyName)
|
|
||||||
{
|
|
||||||
List<LocalPlugin> installedPlugins = await GetInstalledPlugins();
|
|
||||||
|
|
||||||
foreach (var plugin in installedPlugins)
|
|
||||||
{
|
|
||||||
if (plugin.ListOfExecutableDependencies.TryGetValue(dependencyName, out var dependencyPath))
|
|
||||||
{
|
|
||||||
string relativePath = GenerateDependencyRelativePath(plugin.PluginName, dependencyPath);
|
|
||||||
return Response<string>.Success(relativePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response<string>.Failure($"Dependency {dependencyName} not found in the installed plugins.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IResponse<string>> GetDependencyLocation(string dependencyName, string pluginName)
|
|
||||||
{
|
|
||||||
List<LocalPlugin> installedPlugins = await GetInstalledPlugins();
|
|
||||||
|
|
||||||
foreach (var plugin in installedPlugins)
|
|
||||||
{
|
|
||||||
if (plugin.PluginName == pluginName && plugin.ListOfExecutableDependencies.ContainsKey(dependencyName))
|
|
||||||
{
|
|
||||||
string dependencyPath = plugin.ListOfExecutableDependencies[dependencyName];
|
|
||||||
string relativePath = GenerateDependencyRelativePath(pluginName, dependencyPath);
|
|
||||||
return Response<string>.Success(relativePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response<string>.Failure($"Dependency {dependencyName} not found in the installed plugins.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GenerateDependencyRelativePath(string pluginName, string dependencyPath)
|
|
||||||
{
|
|
||||||
string relative = $"./{_LibrariesBaseFolder}/{pluginName}/{dependencyPath}";
|
|
||||||
return relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IResponse<bool>> InstallPlugin(OnlinePlugin plugin, IProgress<float> progress)
|
|
||||||
{
|
|
||||||
string? pluginsFolder = _Configuration.Get<string>("PluginFolder");
|
|
||||||
if (pluginsFolder is null)
|
|
||||||
{
|
|
||||||
return Response.Failure("Plugin folder path is not present in the config file");
|
|
||||||
}
|
|
||||||
|
|
||||||
var localPluginResponse = await GetLocalPluginByName(plugin.Name);
|
|
||||||
if (localPluginResponse is { IsSuccess: true, Data: not null })
|
|
||||||
{
|
|
||||||
var response = await IsNewVersion(localPluginResponse.Data.PluginVersion, plugin.Version);
|
|
||||||
if (!response.IsSuccess)
|
|
||||||
{
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<OnlineDependencyInfo> dependencies = await _PluginRepository.GetDependenciesForPlugin(plugin.Id);
|
|
||||||
|
|
||||||
string downloadLocation = $"{pluginsFolder}/{plugin.Name}.dll";
|
|
||||||
|
|
||||||
IProgress<float> downloadProgress = new Progress<float>(progress.Report);
|
|
||||||
|
|
||||||
FileDownloader fileDownloader = new FileDownloader(plugin.DownloadLink, downloadLocation);
|
|
||||||
await fileDownloader.DownloadFile(downloadProgress.Report);
|
|
||||||
|
|
||||||
ParallelDownloadExecutor executor = new ParallelDownloadExecutor();
|
|
||||||
|
|
||||||
foreach (var dependency in dependencies)
|
|
||||||
{
|
|
||||||
string dependencyLocation = GenerateDependencyRelativePath(plugin.Name, dependency.DownloadLocation);
|
|
||||||
|
|
||||||
executor.AddTask(dependency.DownloadLink, dependencyLocation, progress.Report);
|
|
||||||
}
|
|
||||||
|
|
||||||
await executor.ExecuteAllTasks();
|
|
||||||
|
|
||||||
LocalPlugin localPlugin = LocalPlugin.FromOnlineInfo(plugin, dependencies, downloadLocation);
|
|
||||||
var result = await AppendPluginToDatabase(localPlugin);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SetEnabledStatus(string pluginName, bool status)
|
|
||||||
{
|
|
||||||
var plugins = await GetInstalledPlugins();
|
|
||||||
var plugin = plugins.Find(p => p.PluginName == pluginName);
|
|
||||||
|
|
||||||
if (plugin == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
plugin.IsEnabled = status;
|
|
||||||
|
|
||||||
await RemovePluginFromDatabase(pluginName);
|
|
||||||
await AppendPluginToDatabase(plugin);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IResponse<bool>> UninstallPluginByName(string pluginName)
|
|
||||||
{
|
|
||||||
var localPluginResponse = await GetLocalPluginByName(pluginName);
|
|
||||||
if (!localPluginResponse.IsSuccess)
|
|
||||||
{
|
|
||||||
return Response.Failure(localPluginResponse.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
var localPlugin = localPluginResponse.Data;
|
|
||||||
|
|
||||||
if (localPlugin is null)
|
|
||||||
{
|
|
||||||
return Response.Failure($"Plugin {pluginName} not found in the database");
|
|
||||||
}
|
|
||||||
|
|
||||||
File.Delete(localPlugin.FilePath);
|
|
||||||
|
|
||||||
if (Directory.Exists($"./{_LibrariesBaseFolder}/{pluginName}"))
|
|
||||||
{
|
|
||||||
foreach (var file in Directory.EnumerateFiles($"./{_LibrariesBaseFolder}/{pluginName}"))
|
|
||||||
{
|
|
||||||
File.Delete(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = await RemovePluginFromDatabase(pluginName);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IResponse<LocalPlugin>> GetLocalPluginByName(string pluginName)
|
|
||||||
{
|
|
||||||
List<LocalPlugin> installedPlugins = await GetInstalledPlugins();
|
|
||||||
var plugin = installedPlugins.Find(p => p.PluginName == pluginName);
|
|
||||||
|
|
||||||
if (plugin is null)
|
|
||||||
{
|
|
||||||
return Response<LocalPlugin>.Failure($"Plugin {pluginName} not found in the database");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response<LocalPlugin>.Success(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IResponse<bool>> IsNewVersion(string currentVersion, string newVersion)
|
|
||||||
{
|
|
||||||
// currentVersion = "1.0.0"
|
|
||||||
// newVersion = "1.0.1"
|
|
||||||
|
|
||||||
var currentVersionParts = currentVersion.Split('.').Select(int.Parse).ToArray();
|
|
||||||
var newVersionParts = newVersion.Split('.').Select(int.Parse).ToArray();
|
|
||||||
|
|
||||||
if (currentVersionParts.Length != 3 || newVersionParts.Length != 3)
|
|
||||||
{
|
|
||||||
return Response.Failure("Invalid version format");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
if (newVersionParts[i] > currentVersionParts[i])
|
|
||||||
{
|
|
||||||
return Response.Success();
|
|
||||||
}
|
|
||||||
else if (newVersionParts[i] < currentVersionParts[i])
|
|
||||||
{
|
|
||||||
return Response.Failure("Current version is newer");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.Failure("Versions are the same");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> CreateEmptyPluginDatabase()
|
|
||||||
{
|
|
||||||
string ? pluginDatabaseFile = _Configuration.Get<string>("PluginDatabase");
|
|
||||||
if (pluginDatabaseFile is null)
|
|
||||||
{
|
|
||||||
_Logger.Log("Plugin database file path is not present in the config file", this, LogType.Warning);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (File.Exists(pluginDatabaseFile))
|
|
||||||
{
|
|
||||||
_Logger.Log("Plugin database file already exists", this, LogType.Warning);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<LocalPlugin> installedPlugins = new List<LocalPlugin>();
|
|
||||||
await JsonManager.SaveToJsonFile(pluginDatabaseFile, installedPlugins);
|
|
||||||
_Logger.Log("Plugin database file created", this, LogType.Info);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
using System.IO.Compression;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
using DiscordBotCore.Configuration;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Utilities;
|
|
||||||
|
|
||||||
public class ArchiveManager
|
|
||||||
{
|
|
||||||
private readonly ILogger _Logger;
|
|
||||||
private readonly IConfiguration _Configuration;
|
|
||||||
|
|
||||||
public ArchiveManager(ILogger logger, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
_Logger = logger;
|
|
||||||
_Configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CreateFromFile(string file, string folder)
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(folder))
|
|
||||||
Directory.CreateDirectory(folder);
|
|
||||||
|
|
||||||
var archiveName = folder + Path.GetFileNameWithoutExtension(file) + ".zip";
|
|
||||||
if (File.Exists(archiveName))
|
|
||||||
File.Delete(archiveName);
|
|
||||||
|
|
||||||
using ZipArchive archive = ZipFile.Open(archiveName, ZipArchiveMode.Create);
|
|
||||||
archive.CreateEntryFromFile(file, Path.GetFileName(file));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read a file from a zip archive. The output is a byte array
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileName">The file name in the archive</param>
|
|
||||||
/// <param name="archName">The archive location on the disk</param>
|
|
||||||
/// <returns>An array of bytes that represents the Stream value from the file that was read inside the archive</returns>
|
|
||||||
public async Task<byte[]?> ReadAllBytes(string fileName, string archName)
|
|
||||||
{
|
|
||||||
string? archiveFolderBasePath = _Configuration.Get<string>("ArchiveFolder");
|
|
||||||
if(archiveFolderBasePath is null)
|
|
||||||
throw new Exception("Archive folder not found");
|
|
||||||
|
|
||||||
Directory.CreateDirectory(archiveFolderBasePath);
|
|
||||||
|
|
||||||
archName = Path.Combine(archiveFolderBasePath, archName);
|
|
||||||
|
|
||||||
if (!File.Exists(archName))
|
|
||||||
throw new Exception("Failed to load file !");
|
|
||||||
|
|
||||||
using var zip = ZipFile.OpenRead(archName);
|
|
||||||
var entry = zip.Entries.FirstOrDefault(entry => entry.FullName == fileName || entry.Name == fileName);
|
|
||||||
if (entry is null) throw new Exception("File not found in archive");
|
|
||||||
|
|
||||||
await using var memoryStream = new MemoryStream();
|
|
||||||
var stream = entry.Open();
|
|
||||||
await stream.CopyToAsync(memoryStream);
|
|
||||||
var data = memoryStream.ToArray();
|
|
||||||
|
|
||||||
stream.Close();
|
|
||||||
memoryStream.Close();
|
|
||||||
|
|
||||||
Console.WriteLine("Read file from archive: " + fileName);
|
|
||||||
Console.WriteLine("Size: " + data.Length);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read data from a file that is inside an archive (ZIP format)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileName">The file name that is inside the archive or its full path</param>
|
|
||||||
/// <param name="archFile">The archive location from the PAKs folder</param>
|
|
||||||
/// <returns>A string that represents the content of the file or null if the file does not exists or it has no content</returns>
|
|
||||||
public async Task<string?> ReadFromPakAsync(string fileName, string archFile)
|
|
||||||
{
|
|
||||||
string? archiveFolderBasePath = _Configuration.Get<string>("ArchiveFolder");
|
|
||||||
if(archiveFolderBasePath is null)
|
|
||||||
throw new Exception("Archive folder not found");
|
|
||||||
|
|
||||||
Directory.CreateDirectory(archiveFolderBasePath);
|
|
||||||
|
|
||||||
archFile = Path.Combine(archiveFolderBasePath, archFile);
|
|
||||||
|
|
||||||
if (!File.Exists(archFile))
|
|
||||||
throw new Exception("Failed to load file !");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string? textValue = null;
|
|
||||||
using (var fs = new FileStream(archFile, FileMode.Open))
|
|
||||||
using (var zip = new ZipArchive(fs, ZipArchiveMode.Read))
|
|
||||||
{
|
|
||||||
foreach (var entry in zip.Entries)
|
|
||||||
if (entry.Name == fileName || entry.FullName == fileName)
|
|
||||||
using (var s = entry.Open())
|
|
||||||
using (var reader = new StreamReader(s))
|
|
||||||
{
|
|
||||||
textValue = await reader.ReadToEndAsync();
|
|
||||||
reader.Close();
|
|
||||||
s.Close();
|
|
||||||
fs.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return textValue;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_Logger.LogException(ex, this);
|
|
||||||
await Task.Delay(100);
|
|
||||||
return await ReadFromPakAsync(fileName, archFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extract zip to location
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="zip">The zip location</param>
|
|
||||||
/// <param name="folder">The target location</param>
|
|
||||||
/// <param name="progress">The progress that is updated as a file is processed</param>
|
|
||||||
/// <param name="type">The type of progress</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task ExtractArchive(
|
|
||||||
string zip, string folder, IProgress<float> progress,
|
|
||||||
UnzipProgressType type)
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(folder);
|
|
||||||
using var archive = ZipFile.OpenRead(zip);
|
|
||||||
var totalZipFiles = archive.Entries.Count();
|
|
||||||
if (type == UnzipProgressType.PercentageFromNumberOfFiles)
|
|
||||||
{
|
|
||||||
var currentZipFile = 0;
|
|
||||||
foreach (var entry in archive.Entries)
|
|
||||||
{
|
|
||||||
if (entry.FullName.EndsWith("/")) // it is a folder
|
|
||||||
Directory.CreateDirectory(Path.Combine(folder, entry.FullName));
|
|
||||||
|
|
||||||
else
|
|
||||||
try
|
|
||||||
{
|
|
||||||
entry.ExtractToFile(Path.Combine(folder, entry.FullName), true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_Logger.LogException(ex, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentZipFile++;
|
|
||||||
await Task.Delay(10);
|
|
||||||
if (progress != null)
|
|
||||||
progress.Report((float)currentZipFile / totalZipFiles * 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == UnzipProgressType.PercentageFromTotalSize)
|
|
||||||
{
|
|
||||||
ulong zipSize = 0;
|
|
||||||
|
|
||||||
foreach (var entry in archive.Entries)
|
|
||||||
zipSize += (ulong)entry.CompressedLength;
|
|
||||||
|
|
||||||
ulong currentSize = 0;
|
|
||||||
foreach (var entry in archive.Entries)
|
|
||||||
{
|
|
||||||
if (entry.FullName.EndsWith("/"))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(Path.Combine(folder, entry.FullName));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string path = Path.Combine(folder, entry.FullName);
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
|
||||||
|
|
||||||
entry.ExtractToFile(path, true);
|
|
||||||
currentSize += (ulong)entry.CompressedLength;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_Logger.LogException(ex, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(10);
|
|
||||||
if (progress != null)
|
|
||||||
progress.Report((float)currentSize / zipSize * 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<Platforms>AnyCPU;x64;ARM64</Platforms>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Configuration\DiscordBotCore.Configuration.csproj" />
|
|
||||||
<ProjectReference Include="..\DiscordBotCore.Logging\DiscordBotCore.Logging.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Utilities;
|
|
||||||
|
|
||||||
public static class JsonManager
|
|
||||||
{
|
|
||||||
|
|
||||||
public static async Task<string> ConvertToJson<T>(List<T> data, string[] propertyNamesToUse)
|
|
||||||
{
|
|
||||||
if (data == null) throw new ArgumentNullException(nameof(data));
|
|
||||||
if (propertyNamesToUse == null) throw new ArgumentNullException(nameof(propertyNamesToUse));
|
|
||||||
|
|
||||||
// Use reflection to filter properties dynamically
|
|
||||||
var filteredData = data.Select(item =>
|
|
||||||
{
|
|
||||||
if (item == null) return null;
|
|
||||||
|
|
||||||
var type = typeof(T);
|
|
||||||
var propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
|
|
||||||
// Create a dictionary with specified properties and their values
|
|
||||||
var selectedProperties = propertyInfos
|
|
||||||
.Where(p => propertyNamesToUse.Contains(p.Name))
|
|
||||||
.ToDictionary(p => p.Name, p => p.GetValue(item));
|
|
||||||
|
|
||||||
return selectedProperties;
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
// Serialize the filtered data to JSON
|
|
||||||
var options = new JsonSerializerOptions
|
|
||||||
{
|
|
||||||
WriteIndented = true, // For pretty-print JSON; remove if not needed
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
|
||||||
};
|
|
||||||
|
|
||||||
return await Task.FromResult(JsonSerializer.Serialize(filteredData, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<string> ConvertToJsonString<T>(T Data)
|
|
||||||
{
|
|
||||||
var str = new MemoryStream();
|
|
||||||
await JsonSerializer.SerializeAsync(str, Data, typeof(T), new JsonSerializerOptions
|
|
||||||
{
|
|
||||||
WriteIndented = false,
|
|
||||||
});
|
|
||||||
var result = Encoding.ASCII.GetString(str.ToArray());
|
|
||||||
await str.FlushAsync();
|
|
||||||
str.Close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Save to JSON file
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The class type</typeparam>
|
|
||||||
/// <param name="file">The file path</param>
|
|
||||||
/// <param name="Data">The values</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task SaveToJsonFile<T>(string file, T Data)
|
|
||||||
{
|
|
||||||
var str = new MemoryStream();
|
|
||||||
await JsonSerializer.SerializeAsync(str, Data, typeof(T), new JsonSerializerOptions
|
|
||||||
{
|
|
||||||
WriteIndented = true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
await File.WriteAllBytesAsync(file, str.ToArray());
|
|
||||||
await str.FlushAsync();
|
|
||||||
str.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Convert json text or file to some kind of data
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The data type</typeparam>
|
|
||||||
/// <param name="input">The file or json text</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<T> ConvertFromJson<T>(string input)
|
|
||||||
{
|
|
||||||
Stream text;
|
|
||||||
if (File.Exists(input))
|
|
||||||
text = new MemoryStream(await File.ReadAllBytesAsync(input));
|
|
||||||
else
|
|
||||||
text = new MemoryStream(Encoding.ASCII.GetBytes(input));
|
|
||||||
|
|
||||||
text.Position = 0;
|
|
||||||
|
|
||||||
JsonSerializerOptions options = new JsonSerializerOptions()
|
|
||||||
{
|
|
||||||
PropertyNameCaseInsensitive = true
|
|
||||||
};
|
|
||||||
|
|
||||||
var obj = await JsonSerializer.DeserializeAsync<T>(text, options);
|
|
||||||
await text.FlushAsync();
|
|
||||||
text.Close();
|
|
||||||
|
|
||||||
return (obj ?? default)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
namespace DiscordBotCore.Utilities;
|
|
||||||
|
|
||||||
public class OneOf<T0, T1>
|
|
||||||
{
|
|
||||||
public T0 Item0 { get; }
|
|
||||||
public T1 Item1 { get; }
|
|
||||||
|
|
||||||
public object? Value => Item0 != null ? Item0 : Item1;
|
|
||||||
|
|
||||||
public OneOf(T0 item0)
|
|
||||||
{
|
|
||||||
Item0 = item0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OneOf(T1 item1)
|
|
||||||
{
|
|
||||||
Item1 = item1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator OneOf<T0, T1>(T0 item0) => new OneOf<T0, T1>(item0);
|
|
||||||
public static implicit operator OneOf<T0, T1>(T1 item1) => new OneOf<T0, T1>(item1);
|
|
||||||
|
|
||||||
public void Match(Action<T0> item0, Action<T1> item1)
|
|
||||||
{
|
|
||||||
if (Item0 != null)
|
|
||||||
item0(Item0);
|
|
||||||
else
|
|
||||||
item1(Item1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TResult Match<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1)
|
|
||||||
{
|
|
||||||
return Item0 != null ? item0(Item0) : item1(Item1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type GetActualType()
|
|
||||||
{
|
|
||||||
return Item0 != null ? Item0.GetType() : Item1.GetType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OneOf<T0, T1, T2>
|
|
||||||
{
|
|
||||||
public T0 Item0 { get; }
|
|
||||||
public T1 Item1 { get; }
|
|
||||||
public T2 Item2 { get; }
|
|
||||||
|
|
||||||
public OneOf(T0 item0)
|
|
||||||
{
|
|
||||||
Item0 = item0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OneOf(T1 item1)
|
|
||||||
{
|
|
||||||
Item1 = item1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OneOf(T2 item2)
|
|
||||||
{
|
|
||||||
Item2 = item2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator OneOf<T0, T1, T2>(T0 item0) => new OneOf<T0, T1, T2>(item0);
|
|
||||||
public static implicit operator OneOf<T0, T1, T2>(T1 item1) => new OneOf<T0, T1, T2>(item1);
|
|
||||||
public static implicit operator OneOf<T0, T1, T2>(T2 item2) => new OneOf<T0, T1, T2>(item2);
|
|
||||||
|
|
||||||
public void Match(Action<T0> item0, Action<T1> item1, Action<T2> item2)
|
|
||||||
{
|
|
||||||
if (Item0 != null)
|
|
||||||
item0(Item0);
|
|
||||||
else if (Item1 != null)
|
|
||||||
item1(Item1);
|
|
||||||
else
|
|
||||||
item2(Item2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TResult Match<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1, Func<T2, TResult> item2)
|
|
||||||
{
|
|
||||||
return Item0 != null ? item0(Item0) : Item1 != null ? item1(Item1) : item2(Item2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OneOf<T0, T1, T2, T3>
|
|
||||||
{
|
|
||||||
public T0 Item0 { get; }
|
|
||||||
public T1 Item1 { get; }
|
|
||||||
public T2 Item2 { get; }
|
|
||||||
public T3 Item3 { get; }
|
|
||||||
|
|
||||||
public OneOf(T0 item0)
|
|
||||||
{
|
|
||||||
Item0 = item0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OneOf(T1 item1)
|
|
||||||
{
|
|
||||||
Item1 = item1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OneOf(T2 item2)
|
|
||||||
{
|
|
||||||
Item2 = item2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OneOf(T3 item3)
|
|
||||||
{
|
|
||||||
Item3 = item3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator OneOf<T0, T1, T2, T3>(T0 item0) => new OneOf<T0, T1, T2, T3>(item0);
|
|
||||||
public static implicit operator OneOf<T0, T1, T2, T3>(T1 item1) => new OneOf<T0, T1, T2, T3>(item1);
|
|
||||||
public static implicit operator OneOf<T0, T1, T2, T3>(T2 item2) => new OneOf<T0, T1, T2, T3>(item2);
|
|
||||||
public static implicit operator OneOf<T0, T1, T2, T3>(T3 item3) => new OneOf<T0, T1, T2, T3>(item3);
|
|
||||||
|
|
||||||
public void Match(Action<T0> item0, Action<T1> item1, Action<T2> item2, Action<T3> item3)
|
|
||||||
{
|
|
||||||
if (Item0 != null)
|
|
||||||
item0(Item0);
|
|
||||||
else if (Item1 != null)
|
|
||||||
item1(Item1);
|
|
||||||
else if (Item2 != null)
|
|
||||||
item2(Item2);
|
|
||||||
else
|
|
||||||
item3(Item3);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TResult Match<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1, Func<T2, TResult> item2, Func<T3, TResult> item3)
|
|
||||||
{
|
|
||||||
return Item0 != null ? item0(Item0) : Item1 != null ? item1(Item1) : Item2 != null ? item2(Item2) : item3(Item3);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
namespace DiscordBotCore.Utilities;
|
|
||||||
|
|
||||||
public class OperatingSystem
|
|
||||||
{
|
|
||||||
public enum OperatingSystemEnum : int
|
|
||||||
{
|
|
||||||
Windows = 0,
|
|
||||||
Linux = 1,
|
|
||||||
MacOs = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
public static OperatingSystemEnum GetOperatingSystem()
|
|
||||||
{
|
|
||||||
if(System.OperatingSystem.IsLinux()) return OperatingSystemEnum.Linux;
|
|
||||||
if(System.OperatingSystem.IsWindows()) return OperatingSystemEnum.Windows;
|
|
||||||
if(System.OperatingSystem.IsMacOS()) return OperatingSystemEnum.MacOs;
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetOperatingSystemString(OperatingSystemEnum os)
|
|
||||||
{
|
|
||||||
return os switch
|
|
||||||
{
|
|
||||||
OperatingSystemEnum.Windows => "Windows",
|
|
||||||
OperatingSystemEnum.Linux => "Linux",
|
|
||||||
OperatingSystemEnum.MacOs => "MacOS",
|
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static OperatingSystemEnum GetOperatingSystemFromString(string os)
|
|
||||||
{
|
|
||||||
return os.ToLower() switch
|
|
||||||
{
|
|
||||||
"windows" => OperatingSystemEnum.Windows,
|
|
||||||
"linux" => OperatingSystemEnum.Linux,
|
|
||||||
"macos" => OperatingSystemEnum.MacOs,
|
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetOperatingSystemInt()
|
|
||||||
{
|
|
||||||
return (int) GetOperatingSystem();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,258 +0,0 @@
|
|||||||
namespace DiscordBotCore.Utilities;
|
|
||||||
public class Option2<T0, T1, TError> where TError : Exception
|
|
||||||
{
|
|
||||||
private readonly int _Index;
|
|
||||||
|
|
||||||
private T0 Item0 { get; } = default!;
|
|
||||||
private T1 Item1 { get; } = default!;
|
|
||||||
|
|
||||||
private TError Error { get; } = default!;
|
|
||||||
|
|
||||||
public Option2(T0 item0)
|
|
||||||
{
|
|
||||||
Item0 = item0;
|
|
||||||
_Index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option2(T1 item1)
|
|
||||||
{
|
|
||||||
Item1 = item1;
|
|
||||||
_Index = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option2(TError error)
|
|
||||||
{
|
|
||||||
Error = error;
|
|
||||||
_Index = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator Option2<T0, T1, TError>(T0 item0) => new Option2<T0, T1, TError>(item0);
|
|
||||||
public static implicit operator Option2<T0, T1, TError>(T1 item1) => new Option2<T0, T1, TError>(item1);
|
|
||||||
public static implicit operator Option2<T0, T1, TError>(TError error) => new Option2<T0, T1, TError>(error);
|
|
||||||
|
|
||||||
public void Match(Action<T0> item0, Action<T1> item1, Action<TError> error)
|
|
||||||
{
|
|
||||||
switch (_Index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
item0(Item0);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
item1(Item1);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
error(Error);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TResult Match<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1, Func<TError, TResult> error)
|
|
||||||
{
|
|
||||||
return _Index switch
|
|
||||||
{
|
|
||||||
0 => item0(Item0),
|
|
||||||
1 => item1(Item1),
|
|
||||||
2 => error(Error),
|
|
||||||
_ => throw new InvalidOperationException(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return _Index switch
|
|
||||||
{
|
|
||||||
0 => $"Option2<{typeof(T0).Name}>: {Item0}",
|
|
||||||
1 => $"Option2<{typeof(T1).Name}>: {Item1}",
|
|
||||||
2 => $"Option2<{typeof(TError).Name}>: {Error}",
|
|
||||||
_ => "Invalid Option2"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Option3<T0, T1, T2, TError> where TError : Exception
|
|
||||||
{
|
|
||||||
private readonly int _Index;
|
|
||||||
|
|
||||||
private T0 Item0 { get; } = default!;
|
|
||||||
private T1 Item1 { get; } = default!;
|
|
||||||
private T2 Item2 { get; } = default!;
|
|
||||||
private TError Error { get; } = default!;
|
|
||||||
|
|
||||||
public Option3(T0 item0)
|
|
||||||
{
|
|
||||||
Item0 = item0;
|
|
||||||
_Index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option3(T1 item1)
|
|
||||||
{
|
|
||||||
Item1 = item1;
|
|
||||||
_Index = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option3(T2 item2)
|
|
||||||
{
|
|
||||||
Item2 = item2;
|
|
||||||
_Index = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option3(TError error)
|
|
||||||
{
|
|
||||||
Error = error;
|
|
||||||
_Index = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator Option3<T0, T1, T2, TError>(T0 item0) => new Option3<T0, T1, T2, TError>(item0);
|
|
||||||
public static implicit operator Option3<T0, T1, T2, TError>(T1 item1) => new Option3<T0, T1, T2, TError>(item1);
|
|
||||||
public static implicit operator Option3<T0, T1, T2, TError>(T2 item2) => new Option3<T0, T1, T2, TError>(item2);
|
|
||||||
public static implicit operator Option3<T0, T1, T2, TError>(TError error) => new Option3<T0, T1, T2, TError>(error);
|
|
||||||
|
|
||||||
public void Match(Action<T0> item0, Action<T1> item1, Action<T2> item2, Action<TError> error)
|
|
||||||
{
|
|
||||||
switch (_Index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
item0(Item0);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
item1(Item1);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
item2(Item2);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
error(Error);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TResult Match<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1, Func<T2, TResult> item2, Func<TError, TResult> error)
|
|
||||||
{
|
|
||||||
return _Index switch
|
|
||||||
{
|
|
||||||
0 => item0(Item0),
|
|
||||||
1 => item1(Item1),
|
|
||||||
2 => item2(Item2),
|
|
||||||
3 => error(Error),
|
|
||||||
_ => throw new InvalidOperationException(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return _Index switch
|
|
||||||
{
|
|
||||||
0 => $"Option3<{typeof(T0).Name}>: {Item0}",
|
|
||||||
1 => $"Option3<{typeof(T1).Name}>: {Item1}",
|
|
||||||
2 => $"Option3<{typeof(T2).Name}>: {Item2}",
|
|
||||||
3 => $"Option3<{typeof(TError).Name}>: {Error}",
|
|
||||||
_ => "Invalid Option3"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Option4<T0, T1, T2, T3, TError> where TError : Exception
|
|
||||||
{
|
|
||||||
private readonly int _Index;
|
|
||||||
|
|
||||||
private T0 Item0 { get; } = default!;
|
|
||||||
private T1 Item1 { get; } = default!;
|
|
||||||
private T2 Item2 { get; } = default!;
|
|
||||||
private T3 Item3 { get; } = default!;
|
|
||||||
|
|
||||||
private TError Error { get; } = default!;
|
|
||||||
|
|
||||||
public Option4(T0 item0)
|
|
||||||
{
|
|
||||||
Item0 = item0;
|
|
||||||
_Index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option4(T1 item1)
|
|
||||||
{
|
|
||||||
Item1 = item1;
|
|
||||||
_Index = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option4(T2 item2)
|
|
||||||
{
|
|
||||||
Item2 = item2;
|
|
||||||
_Index = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option4(T3 item3)
|
|
||||||
{
|
|
||||||
Item3 = item3;
|
|
||||||
_Index = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option4(TError error)
|
|
||||||
{
|
|
||||||
Error = error;
|
|
||||||
_Index = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static implicit operator Option4<T0, T1, T2, T3, TError>(T0 item0) => new Option4<T0, T1, T2, T3, TError>(item0);
|
|
||||||
public static implicit operator Option4<T0, T1, T2, T3, TError>(T1 item1) => new Option4<T0, T1, T2, T3, TError>(item1);
|
|
||||||
public static implicit operator Option4<T0, T1, T2, T3, TError>(T2 item2) => new Option4<T0, T1, T2, T3, TError>(item2);
|
|
||||||
public static implicit operator Option4<T0, T1, T2, T3, TError>(T3 item3) => new Option4<T0, T1, T2, T3, TError>(item3);
|
|
||||||
public static implicit operator Option4<T0, T1, T2, T3, TError>(TError error) => new Option4<T0, T1, T2, T3, TError>(error);
|
|
||||||
|
|
||||||
|
|
||||||
public void Match(Action<T0> item0, Action<T1> item1, Action<T2> item2, Action<T3> item3, Action<TError> error)
|
|
||||||
{
|
|
||||||
switch (_Index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
item0(Item0);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
item1(Item1);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
item2(Item2);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
item3(Item3);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
error(Error);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TResult Match<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1, Func<T2, TResult> item2, Func<T3, TResult> item3, Func<TError, TResult> error)
|
|
||||||
{
|
|
||||||
return _Index switch
|
|
||||||
{
|
|
||||||
0 => item0(Item0),
|
|
||||||
1 => item1(Item1),
|
|
||||||
2 => item2(Item2),
|
|
||||||
3 => item3(Item3),
|
|
||||||
4 => error(Error),
|
|
||||||
_ => throw new InvalidOperationException(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return _Index switch
|
|
||||||
{
|
|
||||||
0 => $"Option4<{typeof(T0).Name}>: {Item0}",
|
|
||||||
1 => $"Option4<{typeof(T1).Name}>: {Item1}",
|
|
||||||
2 => $"Option4<{typeof(T2).Name}>: {Item2}",
|
|
||||||
3 => $"Option4<{typeof(T3).Name}>: {Item3}",
|
|
||||||
4 => $"Option4<{typeof(TError).Name}>: {Error}",
|
|
||||||
_ => "Invalid Option4"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace DiscordBotCore.Utilities.Responses;
|
|
||||||
|
|
||||||
public interface IResponse<out T>
|
|
||||||
{
|
|
||||||
public bool IsSuccess { get; }
|
|
||||||
public string Message { get; }
|
|
||||||
public T? Data { get; }
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
namespace DiscordBotCore.Utilities.Responses;
|
|
||||||
|
|
||||||
public class Response : IResponse<bool>
|
|
||||||
{
|
|
||||||
public bool IsSuccess => Data;
|
|
||||||
public string Message { get; }
|
|
||||||
public bool Data { get; }
|
|
||||||
|
|
||||||
private Response(bool result)
|
|
||||||
{
|
|
||||||
Data = result;
|
|
||||||
Message = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Response(string message)
|
|
||||||
{
|
|
||||||
Data = false;
|
|
||||||
Message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Response Success() => new Response(true);
|
|
||||||
public static Response Failure(string message) => new Response(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Response<T> : IResponse<T> where T : class
|
|
||||||
{
|
|
||||||
public bool IsSuccess => Data is not null;
|
|
||||||
public string Message { get; }
|
|
||||||
public T? Data { get; }
|
|
||||||
|
|
||||||
private Response(T data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Message = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Response(string message)
|
|
||||||
{
|
|
||||||
Data = null;
|
|
||||||
Message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Response<T> Success(T data) => new Response<T>(data);
|
|
||||||
public static Response<T> Failure(string message) => new Response<T>(message);
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
namespace DiscordBotCore.Utilities;
|
|
||||||
|
|
||||||
public class Result
|
|
||||||
{
|
|
||||||
private bool? _Result;
|
|
||||||
private Exception? Exception { get; }
|
|
||||||
|
|
||||||
|
|
||||||
private Result(Exception exception)
|
|
||||||
{
|
|
||||||
_Result = null;
|
|
||||||
Exception = exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Result(bool result)
|
|
||||||
{
|
|
||||||
_Result = result;
|
|
||||||
Exception = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSuccess => _Result.HasValue && _Result.Value;
|
|
||||||
|
|
||||||
public void HandleException(Action<Exception> action)
|
|
||||||
{
|
|
||||||
if(IsSuccess)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
action(Exception!);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Result Success() => new Result(true);
|
|
||||||
public static Result Failure(Exception ex) => new Result(ex);
|
|
||||||
public static Result Failure(string message) => new Result(new Exception(message));
|
|
||||||
|
|
||||||
public void Match(Action successAction, Action<Exception> exceptionAction)
|
|
||||||
{
|
|
||||||
if (_Result.HasValue && _Result.Value)
|
|
||||||
{
|
|
||||||
successAction();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exceptionAction(Exception!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TResult Match<TResult>(Func<TResult> successAction, Func<Exception,TResult> errorAction)
|
|
||||||
{
|
|
||||||
return IsSuccess ? successAction() : errorAction(Exception!);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Result<T>
|
|
||||||
{
|
|
||||||
private readonly OneOf<T, Exception> _Result;
|
|
||||||
|
|
||||||
private Result(OneOf<T, Exception> result)
|
|
||||||
{
|
|
||||||
_Result = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Result<T> From (T value) => new Result<T>(new OneOf<T, Exception>(value));
|
|
||||||
public static implicit operator Result<T>(Exception exception) => new Result<T>(new OneOf<T, Exception>(exception));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void Match(Action<T> valueAction, Action<Exception> exceptionAction)
|
|
||||||
{
|
|
||||||
_Result.Match(valueAction, exceptionAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TResult Match<TResult>(Func<T, TResult> valueFunc, Func<Exception, TResult> exceptionFunc)
|
|
||||||
{
|
|
||||||
return _Result.Match(valueFunc, exceptionFunc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace DiscordBotCore.Utilities;
|
|
||||||
|
|
||||||
public enum UnzipProgressType
|
|
||||||
{
|
|
||||||
PercentageFromNumberOfFiles,
|
|
||||||
PercentageFromTotalSize
|
|
||||||
}
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Discord.Commands;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using DiscordBotCore.Configuration;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
using DiscordBotCore.Others;
|
|
||||||
using DiscordBotCore.PluginCore.Helpers;
|
|
||||||
using DiscordBotCore.PluginCore.Helpers.Execution.DbCommand;
|
|
||||||
using DiscordBotCore.PluginCore.Interfaces;
|
|
||||||
using DiscordBotCore.PluginManagement.Loading;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Bot;
|
|
||||||
|
|
||||||
internal class CommandHandler : ICommandHandler
|
|
||||||
{
|
|
||||||
private static readonly string _DefaultPrefix = ";";
|
|
||||||
|
|
||||||
private readonly CommandService _commandService;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
private readonly IPluginLoader _pluginLoader;
|
|
||||||
private readonly IConfiguration _configuration;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Command handler constructor
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginLoader">The plugin loader</param>
|
|
||||||
/// <param name="commandService">The discord bot command service</param>
|
|
||||||
/// <param name="botPrefix">The prefix to watch for</param>
|
|
||||||
/// <param name="logger">The logger</param>
|
|
||||||
public CommandHandler(ILogger logger, IPluginLoader pluginLoader, IConfiguration configuration, CommandService commandService)
|
|
||||||
{
|
|
||||||
_commandService = commandService;
|
|
||||||
_logger = logger;
|
|
||||||
_pluginLoader = pluginLoader;
|
|
||||||
_configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The method to initialize all commands
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task InstallCommandsAsync(DiscordSocketClient client)
|
|
||||||
{
|
|
||||||
client.MessageReceived += (message) => MessageHandler(client, message);
|
|
||||||
client.SlashCommandExecuted += Client_SlashCommandExecuted;
|
|
||||||
await _commandService.AddModulesAsync(Assembly.GetEntryAssembly(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task Client_SlashCommandExecuted(SocketSlashCommand arg)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var plugin = _pluginLoader.SlashCommands.FirstOrDefault(p => p.Name == arg.Data.Name);
|
|
||||||
|
|
||||||
if (plugin is null)
|
|
||||||
throw new Exception("Failed to run command !");
|
|
||||||
|
|
||||||
if (arg.Channel is SocketDMChannel)
|
|
||||||
plugin.ExecuteDm(_logger, arg);
|
|
||||||
else plugin.ExecuteServer(_logger, arg);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogException(ex, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The message handler for the bot
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Message">The message got from the user in discord chat</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private async Task MessageHandler(DiscordSocketClient socketClient, SocketMessage socketMessage)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (socketMessage.Author.IsBot)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (socketMessage as SocketUserMessage == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var message = socketMessage as SocketUserMessage;
|
|
||||||
|
|
||||||
if (message is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var argPos = 0;
|
|
||||||
|
|
||||||
string botPrefix = this._configuration.Get<string>("prefix", _DefaultPrefix);
|
|
||||||
|
|
||||||
if (!message.Content.StartsWith(botPrefix) && !message.HasMentionPrefix(socketClient.CurrentUser, ref argPos))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var context = new SocketCommandContext(socketClient, message);
|
|
||||||
|
|
||||||
await _commandService.ExecuteAsync(context, argPos, null);
|
|
||||||
|
|
||||||
IDbCommand? plugin;
|
|
||||||
var cleanMessage = "";
|
|
||||||
|
|
||||||
if (message.HasMentionPrefix(socketClient.CurrentUser, ref argPos))
|
|
||||||
{
|
|
||||||
var mentionPrefix = "<@" + socketClient.CurrentUser.Id + ">";
|
|
||||||
|
|
||||||
plugin = _pluginLoader.Commands!
|
|
||||||
.FirstOrDefault(plug => plug.Command ==
|
|
||||||
message.Content.Substring(mentionPrefix.Length + 1)
|
|
||||||
.Split(' ')[0] ||
|
|
||||||
plug.Aliases.Contains(message.CleanContent
|
|
||||||
.Substring(mentionPrefix.Length + 1)
|
|
||||||
.Split(' ')[0]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
cleanMessage = message.Content.Substring(mentionPrefix.Length + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
plugin = _pluginLoader.Commands!
|
|
||||||
.FirstOrDefault(p => p.Command ==
|
|
||||||
message.Content.Split(' ')[0].Substring(botPrefix.Length) ||
|
|
||||||
p.Aliases.Contains(
|
|
||||||
message.Content.Split(' ')[0]
|
|
||||||
.Substring(botPrefix.Length)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
cleanMessage = message.Content.Substring(botPrefix.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plugin is null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plugin.RequireAdmin && !context.Message.Author.IsAdmin())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var split = cleanMessage.Split(' ');
|
|
||||||
|
|
||||||
string[]? argsClean = null;
|
|
||||||
if (split.Length > 1)
|
|
||||||
{
|
|
||||||
argsClean = string.Join(' ', split, 1, split.Length - 1).Split(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
DbCommandExecutingArgument cmd = new(_logger,
|
|
||||||
context,
|
|
||||||
cleanMessage,
|
|
||||||
split[0],
|
|
||||||
argsClean,
|
|
||||||
new DirectoryInfo(Path.Combine(_configuration.Get<string>("ResourcesFolder"), plugin.Command)));
|
|
||||||
|
|
||||||
_logger.Log(
|
|
||||||
$"User ({context.User.Username}) from Guild \"{context.Guild.Name}\" executed command \"{cmd.CleanContent}\"",
|
|
||||||
this,
|
|
||||||
LogType.Info
|
|
||||||
);
|
|
||||||
|
|
||||||
if (context.Channel is SocketDMChannel)
|
|
||||||
{
|
|
||||||
await plugin.ExecuteDm(cmd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await plugin.ExecuteServer(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogException(ex, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Discord;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using DiscordBotCore.Configuration;
|
|
||||||
using DiscordBotCore.Logging;
|
|
||||||
using DiscordBotCore.PluginManagement.Loading;
|
|
||||||
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Bot;
|
|
||||||
|
|
||||||
public class DiscordBotApplication : IDiscordBotApplication
|
|
||||||
{
|
|
||||||
internal static IPluginLoader _InternalPluginLoader;
|
|
||||||
|
|
||||||
private CommandHandler _CommandServiceHandler;
|
|
||||||
private CommandService _Service;
|
|
||||||
private readonly ILogger _Logger;
|
|
||||||
private readonly IConfiguration _Configuration;
|
|
||||||
private readonly IPluginLoader _PluginLoader;
|
|
||||||
|
|
||||||
public bool IsReady { get; private set; }
|
|
||||||
|
|
||||||
public DiscordSocketClient Client { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The main Boot constructor
|
|
||||||
/// </summary>
|
|
||||||
public DiscordBotApplication(ILogger logger, IConfiguration configuration, IPluginLoader pluginLoader)
|
|
||||||
{
|
|
||||||
this._Logger = logger;
|
|
||||||
this._Configuration = configuration;
|
|
||||||
this._PluginLoader = pluginLoader;
|
|
||||||
|
|
||||||
_InternalPluginLoader = pluginLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task StopAsync()
|
|
||||||
{
|
|
||||||
if (!IsReady)
|
|
||||||
{
|
|
||||||
_Logger.Log("Can not stop the bot. It is not yet initialized.", this, LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _PluginLoader.UnloadAllPlugins();
|
|
||||||
|
|
||||||
await Client.LogoutAsync();
|
|
||||||
await Client.StopAsync();
|
|
||||||
|
|
||||||
Client.Log -= Log;
|
|
||||||
Client.LoggedIn -= LoggedIn;
|
|
||||||
Client.Ready -= Ready;
|
|
||||||
Client.Disconnected -= Client_Disconnected;
|
|
||||||
|
|
||||||
await Client.DisposeAsync();
|
|
||||||
|
|
||||||
|
|
||||||
IsReady = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The start method for the bot. This method is used to load the bot
|
|
||||||
/// </summary>
|
|
||||||
public async Task StartAsync()
|
|
||||||
{
|
|
||||||
var config = new DiscordSocketConfig
|
|
||||||
{
|
|
||||||
AlwaysDownloadUsers = true,
|
|
||||||
|
|
||||||
//Disable system clock checkup (for responses at slash commands)
|
|
||||||
UseInteractionSnowflakeDate = false,
|
|
||||||
GatewayIntents = GatewayIntents.All
|
|
||||||
};
|
|
||||||
|
|
||||||
DiscordSocketClient client = new DiscordSocketClient(config);
|
|
||||||
|
|
||||||
|
|
||||||
_Service = new CommandService();
|
|
||||||
|
|
||||||
client.Log += Log;
|
|
||||||
client.LoggedIn += LoggedIn;
|
|
||||||
client.Ready += Ready;
|
|
||||||
client.Disconnected += Client_Disconnected;
|
|
||||||
|
|
||||||
Client = client;
|
|
||||||
await client.LoginAsync(TokenType.Bot, _Configuration.Get<string>("token"));
|
|
||||||
await client.StartAsync();
|
|
||||||
|
|
||||||
_CommandServiceHandler = new CommandHandler(_Logger, _PluginLoader, _Configuration, _Service);
|
|
||||||
|
|
||||||
await _CommandServiceHandler.InstallCommandsAsync(client);
|
|
||||||
|
|
||||||
while (!IsReady)
|
|
||||||
{
|
|
||||||
await Task.Delay(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Client_Disconnected(Exception arg)
|
|
||||||
{
|
|
||||||
if (arg.Message.Contains("401"))
|
|
||||||
{
|
|
||||||
_Configuration.Set("token", string.Empty);
|
|
||||||
_Logger.Log("The token is invalid.", this, LogType.Critical);
|
|
||||||
await _Configuration.SaveToFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task Ready()
|
|
||||||
{
|
|
||||||
IsReady = true;
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task LoggedIn()
|
|
||||||
{
|
|
||||||
_Logger.Log("Successfully Logged In", this);
|
|
||||||
_PluginLoader.SetDiscordClient(Client);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task Log(LogMessage message)
|
|
||||||
{
|
|
||||||
switch (message.Severity)
|
|
||||||
{
|
|
||||||
case LogSeverity.Error:
|
|
||||||
case LogSeverity.Critical:
|
|
||||||
_Logger.Log(message.Message, this, LogType.Error);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LogSeverity.Info:
|
|
||||||
case LogSeverity.Debug:
|
|
||||||
_Logger.Log(message.Message, this, LogType.Info);
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Bot;
|
|
||||||
|
|
||||||
internal interface ICommandHandler
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The method to initialize all commands
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task InstallCommandsAsync(DiscordSocketClient client);
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user