Commit b38c262d authored by Him188's avatar Him188

Multiplatform with gradle building

parent 58c6a407
......@@ -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
......@@ -32,3 +32,6 @@ mirai.iml
/.idea/*
/test
.gradle/
\ No newline at end of file
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')
}
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"
}
#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
#!/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" "$@"
@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
apply plugin: "kotlin"
apply plugin: "java"
dependencies {
implementation project(':mirai-core')
implementation project(':mirai-console')
}
<?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>
\ No newline at end of file
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){
......
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) {
}
}
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"
}
\ No newline at end of file
<?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>
\ No newline at end of file
package net.mamoe.mirai;
import lombok.Getter;
/**
* @author NaturalHG
*/
public final class MiraiMain {
@Getter
private static MiraiServer server;
public static void main(String[] args) {
......
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
}
......
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'
}*/
\ No newline at end of file
<?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>
\ No newline at end of file
package net.mamoe.mirai.utils
//todo
\ No newline at end of file
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
......
package net.mamoe.mirai
//expect fun s(): String
/**
* @author Him188moe
*/
object Mirai {
const val VERSION: String = "1.0.0"
}
\ No newline at end of file
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)
}
......
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()
}
\ No newline at end of file
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
}
}
\ No newline at end of file
......@@ -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() {
private suspend fun loginInternal(touchingTimeoutMillis: Long, ipQueue: LinkedList<String>): LoginState {
this.socket.close()
val ip = ipQueue.poll()
if (ip == null) {
future.complete(LoginState.UNKNOWN)//所有服务器均返回 UNKNOWN
return
}
val ip = ipQueue.poll() ?: return LoginState.UNKNOWN//所有服务器均返回 UNKNOWN
this.socket.touch(ip, touchingTimeoutMillis).get().let { state ->
return this.socket.touch(ip, touchingTimeoutMillis).await().let { state ->
if (state == LoginState.UNKNOWN || state == LoginState.TIMEOUT) {
login()//超时或未知, 重试连接下一个服务器
loginInternal(touchingTimeoutMillis, ipQueue)//超时或未知, 重试连接下一个服务器
} else {
future.complete(state)
}
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 {
heartbeatJob = NetworkScope.launch {
delay(90000)
socket.sendPacket(ClientHeartbeatPacket(bot.account.qqNumber, sessionKey))
}
}, 90000, 90000, TimeUnit.MILLISECONDS)
socket.loginFuture!!.complete(LoginState.SUCCESS)
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()
}
\ No newline at end of file
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) {
......
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()
}
}
*/
\ No newline at end of file
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)
}
}
}
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
}
}
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()
}
}
\ No newline at end of file
package net.mamoe.mirai.utils;
package net.mamoe.mirai.utils
/**
* QQ 在线状态
......@@ -6,17 +6,12 @@ package net.mamoe.mirai.utils;
* @author Him188moe
* @see net.mamoe.mirai.network.protocol.tim.packet.login.ClientChangeOnlineStatusPacket
*/
public enum ClientLoginStatus {
enum class ClientLoginStatus(
// TODO: 2019/8/31 add more ClientLoginStatus
val id: Int//1 ubyte
) {
/**
* 我在线上
*/
ONLINE(0x0A);
// TODO: 2019/8/31 add more ClientLoginStatus
public final int id;//1 ubyte
ClientLoginStatus(int id) {
this.id = id;
}
ONLINE(0x0A)
}
package net.mamoe.mirai.utils;
package net.mamoe.mirai.utils
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL
/**
* @author NaturalHG
*/
public class ImageNetworkUtils {
public static boolean postImage(String uKeyHex, int fileSize, long botNumber, long groupCode, byte[] img) throws IOException {
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
String builder = "http://htdata2.qq.com/cgi-bin/httpconn?htcmd=0x6ff0071&ver=5515&term=pc" +
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;
HttpURLConnection conn = (HttpURLConnection) new URL(builder).openConnection();
conn.setRequestProperty("User-Agent", "QQClient");
conn.setRequestProperty("Content-Length", "" + fileSize);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.getOutputStream().write(img);
"&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.getResponseCode() == 200;
conn.connect()
return conn.responseCode == 200
}
}
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 "";
}
}
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);
......
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
/**
......
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>?
}
}
}
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);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment