mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-24 20:43:33 +08:00
Multiplatform with gradle building
This commit is contained in:
parent
58c6a40795
commit
b38c262df0
.gitignorebuild.gradledependencies.gradle
gradle/wrapper
gradlewgradlew.batmirai-api
mirai-console
mirai-core
build.gradlepom.xml
src
commonMain/kotlin/net.mamoe.mirai/utils
jvmMain/kotlin/net/mamoe/mirai
Bot.ktBotHelper.ktMirai.kt
contact
event
message
network
BotNetworkHandler.ktLoginSession.ktNetworkScope.kt
protocol/tim
plugin
task
utils
9
.gitignore
vendored
9
.gitignore
vendored
@ -12,8 +12,6 @@
|
||||
|
||||
# Package Files #
|
||||
*.war
|
||||
*.jar
|
||||
!/mirai-debug/lib/jpcap.jar
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
@ -23,6 +21,8 @@
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
target/
|
||||
build/
|
||||
|
||||
.idea/
|
||||
*.iml
|
||||
@ -31,4 +31,7 @@ mirai.iml
|
||||
.idea/*
|
||||
/.idea/*
|
||||
|
||||
/test
|
||||
/test
|
||||
|
||||
|
||||
.gradle/
|
28
build.gradle
Normal file
28
build.gradle
Normal file
@ -0,0 +1,28 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = "net.mamoe"
|
||||
version = "1.0"
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url "https://mirrors.huaweicloud.com/repository/maven/" }
|
||||
maven { url "http://repo.maven.apache.org/maven2" }
|
||||
}
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
}
|
||||
|
18
dependencies.gradle
Normal file
18
dependencies.gradle
Normal file
@ -0,0 +1,18 @@
|
||||
ext {
|
||||
// dependencies
|
||||
|
||||
// kotlin
|
||||
kotlinJvm = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
kotlinCommon = "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version"
|
||||
|
||||
// coroutine
|
||||
coroutine_version = "1.3.0"
|
||||
coroutine = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version"
|
||||
coroutineCommon = "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutine_version"
|
||||
coroutineNative = "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$coroutine_version"
|
||||
coroutineAndroid = "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"
|
||||
coroutineJs = "org.jetbrains.kotlinx:kotlinx-coroutines-core-js:$coroutine_version"
|
||||
|
||||
// reflect
|
||||
reflect = "org.jetbrains.kotlin:kotlin-reflect:$coroutine_version"
|
||||
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
#Thu Oct 03 14:28:43 CST 2019
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
188
gradlew
vendored
Normal file
188
gradlew
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
100
gradlew.bat
vendored
Normal file
100
gradlew.bat
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
7
mirai-api/build.gradle
Normal file
7
mirai-api/build.gradle
Normal file
@ -0,0 +1,7 @@
|
||||
apply plugin: "kotlin"
|
||||
apply plugin: "java"
|
||||
|
||||
dependencies {
|
||||
implementation project(':mirai-core')
|
||||
implementation project(':mirai-console')
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.mamoe</groupId>
|
||||
<artifactId>mirai</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mirai-api</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.mamoe</groupId>
|
||||
<artifactId>mirai-core</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>net.mamoe</groupId>
|
||||
<artifactId>mirai-console</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>/src/main/resources</directory>
|
||||
|
||||
<includes>
|
||||
<include>**/*.*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -1,13 +1,10 @@
|
||||
package net.mamoe.mirai;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Bot {
|
||||
|
||||
@Getter
|
||||
private final long qq;
|
||||
|
||||
public Bot(long qq){
|
||||
|
@ -1,64 +0,0 @@
|
||||
package net.mamoe.mirai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MiraiAPI provides
|
||||
* - the status of the Mirai-Core
|
||||
* - the fundamental bot operations.
|
||||
* - the plugin status.
|
||||
* <p>
|
||||
* It was designed for users, not developers,
|
||||
* Web-based controller, UI controller or console is depending on Mirai-API
|
||||
* <p>
|
||||
* Mirai-API does NOT contains fancy objects, and this means there are less functions it can do compare with Mirai-Core
|
||||
* <p>
|
||||
* Again, for extending/developing Mirai, you should refer to Mirai-Core
|
||||
* for only using , you should refer to Mirai-API
|
||||
*/
|
||||
public class MiraiAPI {
|
||||
|
||||
public static void startMirai(String[] args) {
|
||||
MiraiMain.main(args);
|
||||
}
|
||||
|
||||
public static void closeMirai() {
|
||||
MiraiServer.INSTANCE.shutdown();
|
||||
}
|
||||
|
||||
public static void restartMirai(String[] args) {
|
||||
MiraiServer.INSTANCE.shutdown();
|
||||
MiraiMain.main(args);
|
||||
}
|
||||
|
||||
public static String getMiraiVersion() {
|
||||
return MiraiServer.MIRAI_VERSION;
|
||||
}
|
||||
|
||||
public static String getQQPortocolVersion() {
|
||||
return MiraiServer.QQ_VERSION;
|
||||
}
|
||||
|
||||
public static boolean isMiraiEnabled() {
|
||||
// TODO: 2019/10/2
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<String> getEnabledPluginList() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public static List<Long> getEnabledBots() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public static Bot getBot(long qq) {
|
||||
return new Bot(qq);
|
||||
}
|
||||
|
||||
public static void addBot(long qq, String password) {
|
||||
|
||||
}
|
||||
|
||||
}
|
18
mirai-console/build.gradle
Normal file
18
mirai-console/build.gradle
Normal file
@ -0,0 +1,18 @@
|
||||
apply plugin: "kotlin"
|
||||
apply plugin: "application"
|
||||
apply plugin: "java"
|
||||
|
||||
dependencies {
|
||||
compile project(':mirai-core')
|
||||
|
||||
compile rootProject.ext.kotlinCommon
|
||||
compile rootProject.ext.kotlinJvm
|
||||
compile rootProject.ext.reflect
|
||||
compile rootProject.ext.coroutine
|
||||
}
|
||||
|
||||
sourceCompatibility = "11"
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.mamoe</groupId>
|
||||
<artifactId>mirai</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mirai-console</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.mamoe</groupId>
|
||||
<artifactId>mirai-core</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlinx</groupId>
|
||||
<artifactId>kotlinx-coroutines-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>/src/main/resources</directory>
|
||||
|
||||
<includes>
|
||||
<include>**/*.*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<jvmTarget>1.8</jvmTarget>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>testCompile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -1,13 +1,10 @@
|
||||
package net.mamoe.mirai;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author NaturalHG
|
||||
*/
|
||||
public final class MiraiMain {
|
||||
@Getter
|
||||
private static MiraiServer server;
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -1,9 +1,7 @@
|
||||
package net.mamoe.mirai
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import lombok.Getter
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginState
|
||||
import net.mamoe.mirai.task.MiraiTaskManager
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.config.MiraiConfig
|
||||
import net.mamoe.mirai.utils.setting.MiraiSettings
|
||||
@ -22,22 +20,11 @@ import java.util.concurrent.ExecutionException
|
||||
* @author NaturalHG
|
||||
*/
|
||||
object MiraiServer {
|
||||
const val MIRAI_VERSION = "1.0.0"
|
||||
|
||||
const val QQ_VERSION = "4.9.0"
|
||||
|
||||
@Getter //is running under UNIX
|
||||
var isUnix: Boolean = false
|
||||
private set
|
||||
|
||||
@Getter
|
||||
var parentFolder: File = File(System.getProperty("user.dir"))
|
||||
|
||||
@Getter
|
||||
var taskManager: MiraiTaskManager
|
||||
internal set
|
||||
|
||||
@Getter
|
||||
var logger: MiraiLogger
|
||||
internal set
|
||||
|
||||
@ -52,9 +39,8 @@ object MiraiServer {
|
||||
this.isUnix = !System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS")
|
||||
|
||||
this.logger = MiraiLogger
|
||||
this.taskManager = MiraiTaskManager.getInstance()
|
||||
|
||||
logger.info("About to run Mirai (" + MiraiServer.MIRAI_VERSION + ") under " + if (isUnix) "unix" else "windows")
|
||||
logger.info("About to run Mirai (" + Mirai.VERSION + ") under " + if (isUnix) "unix" else "windows")
|
||||
logger.info("Loading data under " + LoggerTextFormat.GREEN + this.parentFolder)
|
||||
|
||||
val setting = this.parentFolder + "/Mirai.ini"
|
||||
@ -117,17 +103,17 @@ object MiraiServer {
|
||||
|
||||
this.settings = MiraiSettings(setting)
|
||||
val network = this.settings.getMapSection("network")
|
||||
network.set("enable_proxy", "not supporting yet")
|
||||
network["enable_proxy"] = "not supporting yet"
|
||||
|
||||
val proxy = this.settings.getListSection("proxy")
|
||||
proxy.add("1.2.3.4:95")
|
||||
proxy.add("1.2.3.4:100")
|
||||
|
||||
val worker = this.settings.getMapSection("worker")
|
||||
worker.set("core_task_pool_worker_amount", 5)
|
||||
worker["core_task_pool_worker_amount"] = 5
|
||||
|
||||
val plugin = this.settings.getMapSection("plugin")
|
||||
plugin.set("debug", false)
|
||||
plugin["debug"] = false
|
||||
|
||||
this.settings.save()
|
||||
logger.info("initialized; changing can be made in setting file: $setting")
|
||||
@ -142,7 +128,7 @@ object MiraiServer {
|
||||
private fun reload() {
|
||||
this.enabled = true
|
||||
MiraiLogger.info(LoggerTextFormat.GREEN.toString() + "Server enabled; Welcome to Mirai")
|
||||
MiraiLogger.info("Mirai Version=" + MiraiServer.MIRAI_VERSION + " QQ Version=" + MiraiServer.QQ_VERSION)
|
||||
MiraiLogger.info("Mirai Version=" + Mirai.VERSION)
|
||||
|
||||
MiraiLogger.info("Initializing [Bot]s")
|
||||
|
||||
@ -189,7 +175,7 @@ object MiraiServer {
|
||||
val strings = it.split("----").dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
val bot = Bot(BotAccount(strings[0].toLong(), strings[1]), Console())
|
||||
|
||||
if (runBlocking { bot.network.tryLogin(200).await() } === LoginState.SUCCESS) {
|
||||
if (runBlocking { bot.network.tryLogin(200) } === LoginState.SUCCESS) {
|
||||
bot.green("Login succeed")
|
||||
return bot
|
||||
}
|
||||
|
58
mirai-core/build.gradle
Normal file
58
mirai-core/build.gradle
Normal file
@ -0,0 +1,58 @@
|
||||
apply plugin: "kotlin-multiplatform"
|
||||
|
||||
kotlin {
|
||||
targets {
|
||||
fromPreset(presets.jvm, "jvm")
|
||||
}
|
||||
jvm()
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
// https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-reflect
|
||||
implementation rootProject.ext.kotlinCommon
|
||||
implementation rootProject.ext.reflect
|
||||
implementation rootProject.ext.coroutine
|
||||
implementation rootProject.ext.kotlinJvm
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation rootProject.ext.kotlinJvm
|
||||
implementation rootProject.ext.reflect
|
||||
implementation rootProject.ext.coroutine
|
||||
|
||||
|
||||
implementation 'org.yaml:snakeyaml:1.18'
|
||||
implementation 'org.jsoup:jsoup:1.12.1'
|
||||
implementation 'org.ini4j:ini4j:0.5.2'
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
all {
|
||||
languageSettings.enableLanguageFeature("InlineClasses")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileKotlinJvm{
|
||||
|
||||
}
|
||||
|
||||
configurations {
|
||||
compileClasspath
|
||||
}
|
||||
|
||||
/*
|
||||
dependencies {
|
||||
compile 'com.google.protobuf:protobuf-java:3.5.0'
|
||||
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0-M2'
|
||||
compile 'io.netty:netty-all:4.1.38.Final'
|
||||
compile 'net.java.dev.jna:jna:5.4.0'
|
||||
compile 'org.apache.logging.log4j:log4j-core:2.12.1'
|
||||
compile 'org.yaml:snakeyaml:1.18'
|
||||
compile 'org.jetbrains.kotlin:kotlin-reflect:1.3.41'
|
||||
compile 'org.jsoup:jsoup:1.12.1'
|
||||
compile 'org.ini4j:ini4j:0.5.2'
|
||||
}*/
|
@ -1,118 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>mirai-core</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>net.mamoe</groupId>
|
||||
<artifactId>mirai</artifactId>
|
||||
<version>1.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/jpcap/jpcap -->
|
||||
<dependency>
|
||||
<groupId>jpcap</groupId>
|
||||
<artifactId>jpcap</artifactId>
|
||||
<version>0.1.18-002</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>../mirai-debug/lib/jpcap.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlinx</groupId>
|
||||
<artifactId>kotlinx-coroutines-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ini4j</groupId>
|
||||
<artifactId>ini4j</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>/src/main/resources</directory>
|
||||
|
||||
<includes>
|
||||
<include>**/*.*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<args>
|
||||
<arg>-XXLanguage:+InlineClasses</arg>
|
||||
</args>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,3 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
//todo
|
@ -1,6 +1,5 @@
|
||||
package net.mamoe.mirai
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
|
||||
@ -28,7 +27,7 @@ val Bot.qqs: ContactList<QQ> get() = this.contacts.qqs
|
||||
//NetworkHandler
|
||||
suspend fun Bot.sendPacket(packet: ClientPacket) = this.network.socket.sendPacket(packet)
|
||||
|
||||
fun Bot.login(touchingTimeoutMillis: Long = 200): CompletableDeferred<LoginState> = this.network.tryLogin()
|
||||
suspend fun Bot.login(touchingTimeoutMillis: Long = 200): LoginState = this.network.tryLogin()
|
||||
|
||||
//BotAccount
|
||||
|
9
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/Mirai.kt
Normal file
9
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/Mirai.kt
Normal file
@ -0,0 +1,9 @@
|
||||
package net.mamoe.mirai
|
||||
|
||||
//expect fun s(): String
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
object Mirai {
|
||||
const val VERSION: String = "1.0.0"
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package net.mamoe.mirai.contact
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.message.Message
|
||||
import net.mamoe.mirai.message.defaults.MessageChain
|
||||
@ -24,7 +25,7 @@ abstract class Contact internal constructor(val bot: Bot, val number: Long) {
|
||||
/**
|
||||
* 上传图片
|
||||
*/
|
||||
fun uploadImage(session: LoginSession, image: UnsolvedImage): CompletableFuture<Unit> {
|
||||
fun uploadImage(session: LoginSession, image: UnsolvedImage): CompletableDeferred<Unit> {
|
||||
return image.upload(session, this)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.mamoe.mirai.message.defaults
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
@ -28,7 +29,7 @@ import javax.imageio.ImageIO
|
||||
class UnsolvedImage(filename: String, val image: BufferedImage) : Image(getImageId(filename)) {
|
||||
constructor(imageFile: File) : this(imageFile.name, ImageIO.read(imageFile))
|
||||
constructor(url: URL) : this(File(url.file))
|
||||
fun upload(session: LoginSession, contact: Contact): CompletableFuture<Unit> {
|
||||
fun upload(session: LoginSession, contact: Contact): CompletableDeferred<Unit> {
|
||||
return session.expectPacket<ServerTryGetImageIDResponsePacket> {
|
||||
toSend { ClientTryGetImageIDPacket(session.bot.account.qqNumber, session.sessionKey, contact.number, image) }
|
||||
|
@ -12,7 +12,6 @@ import net.mamoe.mirai.network.protocol.tim.packet.Packet
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginState
|
||||
import java.io.Closeable
|
||||
|
||||
/**
|
||||
* Mirai 的网络处理器, 它承担所有数据包([Packet])的处理任务.
|
||||
@ -32,7 +31,7 @@ import java.io.Closeable
|
||||
*
|
||||
* @author Him188moe
|
||||
*/
|
||||
interface BotNetworkHandler : Closeable {
|
||||
interface BotNetworkHandler {
|
||||
/**
|
||||
* 网络层处理器. 用于编码/解码 [Packet], 发送/接受 [ByteArray]
|
||||
*
|
||||
@ -59,7 +58,7 @@ interface BotNetworkHandler : Closeable {
|
||||
*
|
||||
* @param touchingTimeoutMillis 连接每个服务器的 timeout
|
||||
*/
|
||||
fun tryLogin(touchingTimeoutMillis: Long = 200): CompletableDeferred<LoginState>
|
||||
suspend fun tryLogin(touchingTimeoutMillis: Long = 200): LoginState
|
||||
|
||||
/**
|
||||
* 添加一个临时包处理器
|
||||
@ -68,5 +67,5 @@ interface BotNetworkHandler : Closeable {
|
||||
*/
|
||||
fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*>)
|
||||
|
||||
override fun close()
|
||||
fun close()
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
package net.mamoe.mirai.network
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocket
|
||||
import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
|
||||
import net.mamoe.mirai.utils.getGTK
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* 登录会话. 当登录完成后, 客户端会拿到 sessionKey.
|
||||
@ -58,10 +58,10 @@ class LoginSession(
|
||||
* @return future. 可进行超时处理
|
||||
*/
|
||||
@JvmSynthetic
|
||||
inline fun <reified P : ServerPacket> expectPacket(handlerTemporary: TemporaryPacketHandler<P>.() -> Unit): CompletableFuture<Unit> {
|
||||
val future = CompletableFuture<Unit>()
|
||||
this.bot.network.addHandler(TemporaryPacketHandler(P::class, future, this).also(handlerTemporary))
|
||||
return future
|
||||
inline fun <reified P : ServerPacket> expectPacket(handlerTemporary: TemporaryPacketHandler<P>.() -> Unit): CompletableDeferred<Unit> {
|
||||
val deferred = CompletableDeferred<Unit>()
|
||||
this.bot.network.addHandler(TemporaryPacketHandler(P::class, deferred, this).also(handlerTemporary))
|
||||
return deferred
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,12 +82,12 @@ class LoginSession(
|
||||
* @return future. 可进行超时处理
|
||||
*/
|
||||
@JvmSynthetic
|
||||
inline fun <reified P : ServerPacket> expectPacket(toSend: ClientPacket, noinline handler: suspend (P) -> Unit): CompletableFuture<Unit> {
|
||||
val future = CompletableFuture<Unit>()
|
||||
this.bot.network.addHandler(TemporaryPacketHandler(P::class, future, this).also {
|
||||
inline fun <reified P : ServerPacket> expectPacket(toSend: ClientPacket, noinline handler: suspend (P) -> Unit): CompletableDeferred<Unit> {
|
||||
val deferred = CompletableDeferred<Unit>()
|
||||
this.bot.network.addHandler(TemporaryPacketHandler(P::class, deferred, this).also {
|
||||
it.toSend(toSend)
|
||||
it.onExpect(handler)
|
||||
})
|
||||
return future
|
||||
return deferred
|
||||
}
|
||||
}
|
@ -13,17 +13,12 @@ import net.mamoe.mirai.network.NetworkScope
|
||||
import net.mamoe.mirai.network.protocol.tim.handler.*
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.*
|
||||
import net.mamoe.mirai.task.MiraiThreadPool
|
||||
import net.mamoe.mirai.utils.*
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.net.DatagramPacket
|
||||
import java.net.DatagramSocket
|
||||
import java.net.InetSocketAddress
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.ScheduledFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
/**
|
||||
@ -53,28 +48,21 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
temporaryPacketHandlers.add(temporaryPacketHandler)
|
||||
}
|
||||
|
||||
override fun tryLogin(touchingTimeoutMillis: Long): CompletableDeferred<LoginState> {
|
||||
val ipQueue: LinkedList<String> = LinkedList(TIMProtocol.SERVER_IP)
|
||||
val future = CompletableDeferred<LoginState>()
|
||||
override suspend fun tryLogin(touchingTimeoutMillis: Long): LoginState {
|
||||
return loginInternal(touchingTimeoutMillis, LinkedList(TIMProtocol.SERVER_IP))
|
||||
}
|
||||
|
||||
fun login() {
|
||||
this.socket.close()
|
||||
val ip = ipQueue.poll()
|
||||
if (ip == null) {
|
||||
future.complete(LoginState.UNKNOWN)//所有服务器均返回 UNKNOWN
|
||||
return
|
||||
}
|
||||
private suspend fun loginInternal(touchingTimeoutMillis: Long, ipQueue: LinkedList<String>): LoginState {
|
||||
this.socket.close()
|
||||
val ip = ipQueue.poll() ?: return LoginState.UNKNOWN//所有服务器均返回 UNKNOWN
|
||||
|
||||
this.socket.touch(ip, touchingTimeoutMillis).get().let { state ->
|
||||
if (state == LoginState.UNKNOWN || state == LoginState.TIMEOUT) {
|
||||
login()//超时或未知, 重试连接下一个服务器
|
||||
} else {
|
||||
future.complete(state)
|
||||
}
|
||||
return this.socket.touch(ip, touchingTimeoutMillis).await().let { state ->
|
||||
if (state == LoginState.UNKNOWN || state == LoginState.TIMEOUT) {
|
||||
loginInternal(touchingTimeoutMillis, ipQueue)//超时或未知, 重试连接下一个服务器
|
||||
} else {
|
||||
state
|
||||
}
|
||||
}
|
||||
login()
|
||||
return future
|
||||
}
|
||||
|
||||
//private | internal
|
||||
@ -97,7 +85,7 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
}
|
||||
|
||||
|
||||
internal inner class BotSocket : Closeable, DataPacketSocket {
|
||||
internal inner class BotSocket : DataPacketSocket {
|
||||
override suspend fun distributePacket(packet: ServerPacket) {
|
||||
try {
|
||||
packet.decode()
|
||||
@ -156,7 +144,7 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
restartSocket()
|
||||
}
|
||||
|
||||
internal var loginFuture: CompletableFuture<LoginState>? = null
|
||||
internal var loginResult: CompletableDeferred<LoginState>? = null
|
||||
|
||||
@Synchronized
|
||||
private fun restartSocket() {
|
||||
@ -186,23 +174,23 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
/**
|
||||
* Start network and touch the server
|
||||
*/
|
||||
fun touch(serverAddress: String, timeoutMillis: Long): CompletableFuture<LoginState> {
|
||||
fun touch(serverAddress: String, timeoutMillis: Long): CompletableDeferred<LoginState> {
|
||||
bot.info("Connecting server: $serverAddress")
|
||||
if (this@TIMBotNetworkHandler::login.isInitialized) {
|
||||
login.close()
|
||||
}
|
||||
login = Login()
|
||||
this.loginFuture = CompletableFuture()
|
||||
this.loginResult = CompletableDeferred()
|
||||
|
||||
serverIP = serverAddress
|
||||
bot.waitForPacket(ServerPacket::class, timeoutMillis) {
|
||||
loginFuture!!.complete(LoginState.TIMEOUT)
|
||||
loginResult!!.complete(LoginState.TIMEOUT)
|
||||
}
|
||||
runBlocking {
|
||||
sendPacket(ClientTouchPacket(bot.account.qqNumber, serverIP))
|
||||
}
|
||||
|
||||
return this.loginFuture!!
|
||||
return this.loginResult!!
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,13 +224,14 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
|
||||
override fun getOwner(): Bot = this@TIMBotNetworkHandler.bot
|
||||
|
||||
|
||||
override fun close() {
|
||||
this.socket?.close()
|
||||
if (this.loginFuture != null) {
|
||||
if (!this.loginFuture!!.isDone) {
|
||||
this.loginFuture!!.cancel(true)
|
||||
if (this.loginResult != null) {
|
||||
if (!this.loginResult!!.isCompleted) {
|
||||
this.loginResult!!.cancel(CancellationException("socket closed"))
|
||||
}
|
||||
this.loginFuture = null
|
||||
this.loginResult = null
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,7 +243,7 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
/**
|
||||
* 处理登录过程
|
||||
*/
|
||||
inner class Login : Closeable {
|
||||
inner class Login {
|
||||
private lateinit var token00BA: ByteArray
|
||||
private lateinit var token0825: ByteArray//56
|
||||
private var loginTime: Int = 0
|
||||
@ -269,7 +258,7 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
private var captchaSectionId: Int = 1
|
||||
private var captchaCache: ByteArray? = byteArrayOf()//每次包只发一部分验证码来
|
||||
|
||||
private var heartbeatFuture: ScheduledFuture<*>? = null
|
||||
private var heartbeatJob: Job? = null
|
||||
|
||||
|
||||
suspend fun onPacketReceived(packet: ServerPacket) {
|
||||
@ -289,7 +278,7 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
}
|
||||
|
||||
is ServerLoginResponseFailedPacket -> {
|
||||
socket.loginFuture?.complete(packet.loginState)
|
||||
socket.loginResult?.complete(packet.loginState)
|
||||
bot.close()
|
||||
return
|
||||
}
|
||||
@ -373,13 +362,13 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
|
||||
is ServerSessionKeyResponsePacket -> {
|
||||
sessionKey = packet.sessionKey
|
||||
heartbeatFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
|
||||
runBlocking {
|
||||
socket.sendPacket(ClientHeartbeatPacket(bot.account.qqNumber, sessionKey))
|
||||
}
|
||||
}, 90000, 90000, TimeUnit.MILLISECONDS)
|
||||
|
||||
socket.loginFuture!!.complete(LoginState.SUCCESS)
|
||||
heartbeatJob = NetworkScope.launch {
|
||||
delay(90000)
|
||||
socket.sendPacket(ClientHeartbeatPacket(bot.account.qqNumber, sessionKey))
|
||||
}
|
||||
|
||||
socket.loginResult!!.complete(LoginState.SUCCESS)
|
||||
|
||||
login.changeOnlineStatus(ClientLoginStatus.ONLINE)
|
||||
}
|
||||
@ -420,12 +409,12 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler {
|
||||
socket.sendPacket(ClientChangeOnlineStatusPacket(bot.account.qqNumber, sessionKey, status))
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
fun close() {
|
||||
this.captchaCache = null
|
||||
|
||||
this.heartbeatFuture?.cancel(true)
|
||||
this.heartbeatJob?.cancel(CancellationException("handler closed"))
|
||||
|
||||
this.heartbeatFuture = null
|
||||
this.heartbeatJob = null
|
||||
}
|
||||
}
|
||||
}
|
@ -66,7 +66,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
|
||||
session.sKey = packet.sKey
|
||||
session.cookies = "uin=o" + session.bot.account.qqNumber + ";skey=" + session.sKey + ";"
|
||||
|
||||
sKeyRefresherFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
|
||||
sKeyRefresherFuture = MiraiThreadPool.instance.scheduleWithFixedDelay({
|
||||
runBlocking {
|
||||
session.socket.sendPacket(ClientSKeyRefreshmentRequestPacket(session.bot.account.qqNumber, session.sessionKey))
|
||||
}
|
@ -6,7 +6,6 @@ import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
|
||||
import net.mamoe.mirai.network.LoginSession
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
|
||||
import java.io.Closeable
|
||||
|
||||
/**
|
||||
* 网络接口.
|
||||
@ -15,7 +14,7 @@ import java.io.Closeable
|
||||
*
|
||||
* @author Him188moe
|
||||
*/
|
||||
interface DataPacketSocket : Closeable {
|
||||
interface DataPacketSocket {
|
||||
fun getOwner(): Bot
|
||||
|
||||
/**
|
||||
@ -34,5 +33,5 @@ interface DataPacketSocket : Closeable {
|
||||
|
||||
fun isClosed(): Boolean
|
||||
|
||||
override fun close()
|
||||
fun close()
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package net.mamoe.mirai.network.protocol.tim.handler
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import net.mamoe.mirai.network.LoginSession
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
|
||||
@ -21,7 +22,7 @@ import kotlin.reflect.KClass
|
||||
*/
|
||||
open class TemporaryPacketHandler<P : ServerPacket>(
|
||||
private val expectationClass: KClass<P>,
|
||||
private val future: CompletableFuture<Unit>,
|
||||
private val deferred: CompletableDeferred<Unit>,
|
||||
private val fromSession: LoginSession
|
||||
) {
|
||||
private lateinit var toSend: ClientPacket
|
||||
@ -53,7 +54,7 @@ open class TemporaryPacketHandler<P : ServerPacket>(
|
||||
if (expectationClass.isInstance(packet) && session === this.fromSession) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
expect(packet as P)
|
||||
future.complete(Unit)
|
||||
deferred.complete(Unit)
|
||||
return true
|
||||
}
|
||||
return false
|
@ -2,7 +2,6 @@
|
||||
|
||||
package net.mamoe.mirai.network.protocol.tim.packet
|
||||
|
||||
import lombok.Getter
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.PacketNameFormatter.adjustName
|
||||
import net.mamoe.mirai.utils.*
|
||||
@ -16,7 +15,6 @@ import java.security.MessageDigest
|
||||
*/
|
||||
|
||||
abstract class ClientPacket : ByteArrayDataOutputStream(), Packet {
|
||||
@Getter
|
||||
val idHex: String
|
||||
|
||||
private var encoded: Boolean = false
|
@ -347,7 +347,7 @@ internal fun <P : ServerPacket> Bot.waitForPacket(packetClass: KClass<P>, timeou
|
||||
}
|
||||
|
||||
|
||||
MiraiThreadPool.getInstance().submit {
|
||||
MiraiThreadPool.instance.submit {
|
||||
val startingTime = System.currentTimeMillis()
|
||||
while (!got) {
|
||||
if (System.currentTimeMillis() - startingTime > timeoutMillis) {
|
@ -0,0 +1,135 @@
|
||||
package net.mamoe.mirai.task
|
||||
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.Future
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.function.Consumer
|
||||
import java.util.function.Predicate
|
||||
|
||||
/**
|
||||
* @author NaturalHG
|
||||
*/
|
||||
|
||||
/*
|
||||
class MiraiTaskManager private constructor() {
|
||||
|
||||
private val pool: MiraiThreadPool
|
||||
|
||||
init {
|
||||
this.pool = MiraiThreadPool()
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础Future处理
|
||||
*/
|
||||
|
||||
fun execute(runnable: Runnable) {
|
||||
this.execute(runnable, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun execute(runnable: Runnable, handler: MiraiTaskExceptionHandler) {
|
||||
this.pool.execute {
|
||||
try {
|
||||
runnable.run()
|
||||
} catch (e: Exception) {
|
||||
handler.onHandle(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun <D> submit(callable: Callable<D>): Future<D> {
|
||||
return this.submit(callable, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun <D> submit(callable: Callable<D>, handler: MiraiTaskExceptionHandler): Future<D> {
|
||||
return this.pool.submit<D> {
|
||||
try {
|
||||
callable.call()
|
||||
} catch (e: Throwable) {
|
||||
handler.onHandle(e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步任务
|
||||
*/
|
||||
fun <D> ansycTask(callable: Callable<D>, callback: Consumer<D>) {
|
||||
this.ansycTask(callable, callback, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun <D> ansycTask(callable: Callable<D>, callback: Consumer<D>, handler: MiraiTaskExceptionHandler) {
|
||||
this.pool.execute {
|
||||
try {
|
||||
callback.accept(callable.call())
|
||||
} catch (e: Throwable) {
|
||||
handler.onHandle(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务
|
||||
*/
|
||||
|
||||
fun repeatingTask(runnable: Runnable, intervalMillis: Long) {
|
||||
this.repeatingTask(runnable, intervalMillis, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun repeatingTask(runnable: Runnable, intervalMillis: Long, handler: MiraiTaskExceptionHandler) {
|
||||
this.repeatingTask<Runnable>(runnable, intervalMillis, { a -> true }, handler)
|
||||
}
|
||||
|
||||
fun repeatingTask(runnable: Runnable, intervalMillis: Long, times: Int) {
|
||||
this.repeatingTask(runnable, intervalMillis, times, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun repeatingTask(runnable: Runnable, intervalMillis: Long, times: Int, handler: MiraiTaskExceptionHandler) {
|
||||
val integer = AtomicInteger(times - 1)
|
||||
this.repeatingTask<Runnable>(
|
||||
runnable, intervalMillis, { a -> integer.getAndDecrement() > 0 }, handler
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun <D : Runnable> repeatingTask(runnable: D, intervalMillis: Long, shouldContinue: Predicate<D>, handler: MiraiTaskExceptionHandler) {
|
||||
Thread {
|
||||
do {
|
||||
this.pool.execute {
|
||||
try {
|
||||
runnable.run()
|
||||
} catch (e: Exception) {
|
||||
handler.onHandle(e)
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(intervalMillis)
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
} while (shouldContinue.test(runnable))
|
||||
}.start()
|
||||
}
|
||||
|
||||
fun deletingTask(runnable: Runnable, intervalMillis: Long) {
|
||||
Thread {
|
||||
try {
|
||||
Thread.sleep(intervalMillis)
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
this.pool.execute(runnable)
|
||||
}.start()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val instance = MiraiTaskManager()
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
@ -0,0 +1,35 @@
|
||||
package net.mamoe.mirai.task
|
||||
|
||||
import net.mamoe.mirai.Mirai
|
||||
|
||||
import java.io.Closeable
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor
|
||||
|
||||
/**
|
||||
* @author NaturalHG
|
||||
*/
|
||||
class MiraiThreadPool internal constructor()/*super(0,
|
||||
Integer.MAX_VALUE,
|
||||
60L,
|
||||
TimeUnit.SECONDS,
|
||||
new SynchronousQueue<>()
|
||||
);*/ : ScheduledThreadPoolExecutor(10), Closeable {
|
||||
|
||||
|
||||
override fun close() {
|
||||
this.shutdown()
|
||||
if (!this.isShutdown) {
|
||||
this.shutdownNow()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val instance = MiraiThreadPool()
|
||||
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
println(Mirai.VERSION)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import java.awt.*
|
||||
import java.awt.image.BufferedImage
|
||||
import java.util.ArrayList
|
||||
import java.util.concurrent.Callable
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Convert IMAGE into Chars that could shows in terminal
|
||||
*
|
||||
* @author NaturalHG
|
||||
*/
|
||||
class CharImageConverter @JvmOverloads constructor(
|
||||
/**
|
||||
* width should depends on the width of the terminal
|
||||
*/
|
||||
private var image: BufferedImage?, private val width: Int, private val ignoreRate: Double = 0.95) : Callable<String> {
|
||||
|
||||
override fun call(): String {
|
||||
/*
|
||||
* resize Image
|
||||
* */
|
||||
val newHeight = (this.image!!.getHeight() * (width.toDouble() / this.image!!.getWidth())).toInt()
|
||||
val tmp = image!!.getScaledInstance(width, newHeight, Image.SCALE_SMOOTH)
|
||||
val dimg = BufferedImage(width, newHeight, BufferedImage.TYPE_INT_ARGB)
|
||||
val g2d = dimg.createGraphics()
|
||||
g2d.drawImage(tmp, 0, 0, null)
|
||||
this.image = dimg
|
||||
|
||||
val background = gray(image!!.getRGB(0, 0))
|
||||
|
||||
val builder = StringBuilder()
|
||||
|
||||
val lines = ArrayList<StringBuilder>(this.image!!.getHeight())
|
||||
|
||||
var minXPos = this.width
|
||||
var maxXPos = 0
|
||||
|
||||
for (y in 0 until image!!.getHeight()) {
|
||||
val builderLine = StringBuilder()
|
||||
for (x in 0 until image!!.getWidth()) {
|
||||
val gray = gray(image!!.getRGB(x, y))
|
||||
if (grayCompare(gray, background)) {
|
||||
builderLine.append(" ")
|
||||
} else {
|
||||
builderLine.append("#")
|
||||
if (x < minXPos) {
|
||||
minXPos = x
|
||||
}
|
||||
if (x > maxXPos) {
|
||||
maxXPos = x
|
||||
}
|
||||
}
|
||||
}
|
||||
if (builderLine.toString().isBlank()) {
|
||||
continue
|
||||
}
|
||||
lines.add(builderLine)
|
||||
}
|
||||
for (line in lines) {
|
||||
builder.append(line.substring(minXPos, maxXPos)).append("\n")
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private fun gray(rgb: Int): Int {
|
||||
val R = rgb and 0xff0000 shr 16
|
||||
val G = rgb and 0x00ff00 shr 8
|
||||
val B = rgb and 0x0000ff
|
||||
return (R * 30 + G * 59 + B * 11 + 50) / 100
|
||||
}
|
||||
|
||||
fun grayCompare(g1: Int, g2: Int): Boolean {
|
||||
return min(g1, g2).toDouble() / max(g1, g2) >= ignoreRate
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import java.awt.image.BufferedImage
|
||||
|
||||
/**
|
||||
* @author NaturalHG
|
||||
*/
|
||||
object CharImageUtil {
|
||||
|
||||
@JvmOverloads
|
||||
fun createCharImg(image: BufferedImage, sizeWeight: Int = 100, sizeHeight: Int = 20): String {
|
||||
return CharImageConverter(image, sizeWeight).call()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
/**
|
||||
* QQ 在线状态
|
||||
*
|
||||
* @author Him188moe
|
||||
* @see net.mamoe.mirai.network.protocol.tim.packet.login.ClientChangeOnlineStatusPacket
|
||||
*/
|
||||
enum class ClientLoginStatus(
|
||||
// TODO: 2019/8/31 add more ClientLoginStatus
|
||||
val id: Int//1 ubyte
|
||||
) {
|
||||
/**
|
||||
* 我在线上
|
||||
*/
|
||||
ONLINE(0x0A)
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import java.io.IOException
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* @author NaturalHG
|
||||
*/
|
||||
object ImageNetworkUtils {
|
||||
@Throws(IOException::class)
|
||||
fun postImage(uKeyHex: String, fileSize: Int, botNumber: Long, groupCode: Long, img: ByteArray): Boolean {
|
||||
//http://htdata2.qq.com/cgi-bin/httpconn?htcmd=0x6ff0071&ver=5515&term=pc&ukey=” + 删全部空 (ukey) + “&filesize=” + 到文本 (fileSize) + “&range=0&uin=” + g_uin + “&groupcode=” + Group
|
||||
|
||||
val builder = "http://htdata2.qq.com/cgi-bin/httpconn?htcmd=0x6ff0071&ver=5515&term=pc" +
|
||||
"&ukey=" + uKeyHex.replace(" ", "") +
|
||||
"&filezise=" + fileSize +
|
||||
"&range=" + "0" +
|
||||
"&uin=" + botNumber +
|
||||
"&groupcode=" + groupCode
|
||||
val conn = URL(builder).openConnection() as HttpURLConnection
|
||||
conn.setRequestProperty("User-Agent", "QQClient")
|
||||
conn.setRequestProperty("Content-Length", "" + fileSize)
|
||||
conn.requestMethod = "POST"
|
||||
conn.doOutput = true
|
||||
conn.outputStream.write(img)
|
||||
|
||||
conn.connect()
|
||||
return conn.responseCode == 200
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
/**
|
||||
* @author NaturalHG
|
||||
*/
|
||||
enum class LoggerTextFormat(private val format: String) {
|
||||
RESET("\u001b[0m"),
|
||||
|
||||
BLUE("\u001b[0;34m"),
|
||||
BLACK("\u001b[0;30m"),
|
||||
DARK_GREY("\u001b[1;30m"),
|
||||
LIGHT_BLUE("\u001b[1;34m"),
|
||||
GREEN("\u001b[0;32m"),
|
||||
LIGHT_GTEEN("\u001b[1;32m"),
|
||||
CYAN("\u001b[0;36m"),
|
||||
LIGHT_CYAN("\u001b[1;36m"),
|
||||
RED("\u001b[0;31m"),
|
||||
LIGHT_RED("\u001b[1;31m"),
|
||||
PURPLE("\u001b[0;35m"),
|
||||
LIGHT_PURPLE("\u001b[1;35m"),
|
||||
BROWN("\u001b[0;33m"),
|
||||
YELLOW("\u001b[1;33m"),
|
||||
LIGHT_GRAY("\u001b[0;37m"),
|
||||
WHITE("\u001b[1;37m");
|
||||
|
||||
override fun toString(): String {
|
||||
//if(MiraiServer.getInstance().isUnix()){
|
||||
return format
|
||||
// }
|
||||
// return "";
|
||||
}
|
||||
}
|
@ -1,8 +1,5 @@
|
||||
package net.mamoe.mirai.utils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
@ -54,7 +51,6 @@ public class MiraiSynchronizedLinkedHashMap<K, V> extends AbstractMap<K, V> {
|
||||
return sortedMap.get(key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
return sortedMap.put(key,value);
|
||||
@ -66,7 +62,7 @@ public class MiraiSynchronizedLinkedHashMap<K, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NotNull Map<? extends K, ? extends V> m) {
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
sortedMap.putAll(m);
|
||||
}
|
||||
|
||||
@ -75,19 +71,16 @@ public class MiraiSynchronizedLinkedHashMap<K, V> extends AbstractMap<K, V> {
|
||||
sortedMap.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return sortedMap.keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return sortedMap.values();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return sortedMap.entrySet();
|
||||
@ -113,7 +106,6 @@ public class MiraiSynchronizedLinkedHashMap<K, V> extends AbstractMap<K, V> {
|
||||
return this.sortedMap.replace(key,oldValue,newValue);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V replace(K key, V value) {
|
||||
return this.sortedMap.replace(key,value);
|
||||
@ -144,7 +136,6 @@ public class MiraiSynchronizedLinkedHashMap<K, V> extends AbstractMap<K, V> {
|
||||
return this.sortedMap.hashCode();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V putIfAbsent(K key, V value) {
|
||||
return this.sortedMap.putIfAbsent(key,value);
|
@ -1,7 +1,5 @@
|
||||
package net.mamoe.mirai.utils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntFunction;
|
||||
@ -116,25 +114,21 @@ public class MiraiSynchronizedLinkedList<E> extends AbstractList<E> {
|
||||
return this.syncList.addAll(index, c);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return this.syncList.iterator();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ListIterator<E> listIterator() {
|
||||
return this.syncList.listIterator();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
return this.syncList.listIterator(index);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
return this.syncList.subList(fromIndex, toIndex);
|
||||
@ -155,16 +149,14 @@ public class MiraiSynchronizedLinkedList<E> extends AbstractList<E> {
|
||||
return this.syncList.contains(o);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return this.syncList.toArray();
|
||||
}
|
||||
|
||||
@SuppressWarnings("SuspiciousToArrayCall")
|
||||
@NotNull
|
||||
@Override
|
||||
public <T> T[] toArray(@NotNull T[] a) {
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return this.syncList.toArray(a);
|
||||
}
|
||||
|
||||
@ -174,22 +166,22 @@ public class MiraiSynchronizedLinkedList<E> extends AbstractList<E> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(@NotNull Collection<?> c) {
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return this.syncList.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(@NotNull Collection<? extends E> c) {
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
return this.syncList.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(@NotNull Collection<?> c) {
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return this.syncList.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(@NotNull Collection<?> c) {
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return this.syncList.retainAll(c);
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ import java.util.zip.CRC32
|
||||
import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.GZIPOutputStream
|
||||
import javax.imageio.ImageIO
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
|
||||
|
||||
/**
|
@ -0,0 +1,58 @@
|
||||
package net.mamoe.mirai.utils.config
|
||||
|
||||
import org.yaml.snakeyaml.DumperOptions
|
||||
import org.yaml.snakeyaml.Yaml
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.nio.charset.Charset
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* YAML-TYPE CONFIG
|
||||
* Thread SAFE
|
||||
*
|
||||
* @author NaturalHG
|
||||
*/
|
||||
class MiraiConfig(private val root: File) : MiraiConfigSection<Any>(parse(Objects.requireNonNull(root))) {
|
||||
|
||||
@Synchronized
|
||||
fun save() {
|
||||
val dumperOptions = DumperOptions()
|
||||
dumperOptions.defaultFlowStyle = DumperOptions.FlowStyle.BLOCK
|
||||
val yaml = Yaml(dumperOptions)
|
||||
val content = yaml.dump(this.sortedMap)
|
||||
try {
|
||||
ByteArrayInputStream(content.toByteArray()).transferTo(FileOutputStream(this.root))
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun parse(file: File): MutableMap<String, Any>? {
|
||||
/*
|
||||
if (!file.toURI().getPath().contains(MiraiServer.getInstance().getParentFolder().getPath())) {
|
||||
file = new File(MiraiServer.getInstance().getParentFolder().getPath(), file.getName());
|
||||
}*/
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
if (!file.createNewFile()) {
|
||||
return linkedMapOf()
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
return linkedMapOf()
|
||||
}
|
||||
|
||||
}
|
||||
val dumperOptions = DumperOptions()
|
||||
dumperOptions.defaultFlowStyle = DumperOptions.FlowStyle.BLOCK
|
||||
val yaml = Yaml(dumperOptions)
|
||||
return yaml.loadAs<LinkedHashMap<*, *>>(file.readLines(Charset.defaultCharset()).joinToString("\n"), LinkedHashMap::class.java) as MutableMap<String, Any>?
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package net.mamoe.mirai.utils.config;
|
||||
|
||||
import net.mamoe.mirai.utils.MiraiSynchronizedLinkedHashMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
@ -138,7 +137,6 @@ public class MiraiConfigSection<T> extends MiraiSynchronizedLinkedHashMap<String
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public T put(String key, T value) {
|
||||
return super.put(key, value);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user