mirror of
https://github.com/ChronosX88/InfluenceDHT-Kotlin.git
synced 2024-12-04 15:52:18 +00:00
Made base Kademlia routing
This commit is contained in:
commit
6e9fed4dc6
BIN
.gradle/4.10.3/fileChanges/last-build.bin
Normal file
BIN
.gradle/4.10.3/fileChanges/last-build.bin
Normal file
Binary file not shown.
BIN
.gradle/4.10.3/fileHashes/fileHashes.bin
Normal file
BIN
.gradle/4.10.3/fileHashes/fileHashes.bin
Normal file
Binary file not shown.
BIN
.gradle/4.10.3/fileHashes/fileHashes.lock
Normal file
BIN
.gradle/4.10.3/fileHashes/fileHashes.lock
Normal file
Binary file not shown.
0
.gradle/4.10.3/gc.properties
Normal file
0
.gradle/4.10.3/gc.properties
Normal file
BIN
.gradle/4.10.3/taskHistory/taskHistory.bin
Normal file
BIN
.gradle/4.10.3/taskHistory/taskHistory.bin
Normal file
Binary file not shown.
BIN
.gradle/4.10.3/taskHistory/taskHistory.lock
Normal file
BIN
.gradle/4.10.3/taskHistory/taskHistory.lock
Normal file
Binary file not shown.
BIN
.gradle/buildOutputCleanup/buildOutputCleanup.lock
Normal file
BIN
.gradle/buildOutputCleanup/buildOutputCleanup.lock
Normal file
Binary file not shown.
2
.gradle/buildOutputCleanup/cache.properties
Normal file
2
.gradle/buildOutputCleanup/cache.properties
Normal file
@ -0,0 +1,2 @@
|
||||
#Mon Apr 22 12:19:07 MSK 2019
|
||||
gradle.version=4.10.3
|
BIN
.gradle/buildOutputCleanup/outputFiles.bin
Normal file
BIN
.gradle/buildOutputCleanup/outputFiles.bin
Normal file
Binary file not shown.
0
.gradle/vcs-1/gc.properties
Normal file
0
.gradle/vcs-1/gc.properties
Normal file
1
.idea/.name
Normal file
1
.idea/.name
Normal file
@ -0,0 +1 @@
|
||||
influencedht
|
10
.idea/codeStyles/Project.xml
Normal file
10
.idea/codeStyles/Project.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
17
.idea/gradle.xml
Normal file
17
.idea/gradle.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="useQualifiedModuleNames" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
7
.idea/misc.xml
Normal file
7
.idea/misc.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
618
.idea/workspace.xml
Normal file
618
.idea/workspace.xml
Normal file
@ -0,0 +1,618 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="a3421dfe-66c3-4c54-8bb2-850502ef6dd2" name="Default Changelist" comment="" />
|
||||
<ignored path="$PROJECT_DIR$/out/" />
|
||||
<ignored path="$PROJECT_DIR$/.gradle/" />
|
||||
<ignored path="$PROJECT_DIR$/build/" />
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="DefaultGradleProjectSettings">
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="delegatedBuild" value="true" />
|
||||
<option name="isMigrated" value="true" />
|
||||
</component>
|
||||
<component name="ExternalProjectsData">
|
||||
<projectState path="$PROJECT_DIR$">
|
||||
<ProjectState />
|
||||
</projectState>
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf>
|
||||
<file pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/PeerAddress.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-204">
|
||||
<caret line="44" column="63" selection-start-line="44" selection-start-column="63" selection-end-line="44" selection-end-column="63" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Kotlin File" />
|
||||
<option value="Kotlin Enum" />
|
||||
<option value="Class" />
|
||||
<option value="Kotlin Object" />
|
||||
<option value="Kotlin Class" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="FindInProjectRecents">
|
||||
<findStrings>
|
||||
<find>to</find>
|
||||
<find>toByt</find>
|
||||
</findStrings>
|
||||
</component>
|
||||
<component name="IdeDocumentHistory">
|
||||
<option name="CHANGED_PATHS">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/build.gradle" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/RPCActions.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/rpc/RPCActions.kt" />
|
||||
<option value="$PROJECT_DIR$/settings.gradle" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/KademliaID.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/PeerSocketAddress.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/Node.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/routing/PeerContact.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/java/io/gitub/chronosx88/influencedht/core/Number160.java" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/Utils.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/KadConfig.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/KadConfiguration.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/DefaultIKadConfig.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/IKadConfiguration.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/DefaultKadConfig.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/routing/KademliaBucket.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/KeyComparator.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/routing/KademliaRoutingTable.kt" />
|
||||
<option value="$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/PeerAddress.kt" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectFrameBounds" extendedState="6">
|
||||
<option name="x" value="-25" />
|
||||
<option name="y" value="324" />
|
||||
<option name="width" value="1366" />
|
||||
<option name="height" value="711" />
|
||||
</component>
|
||||
<component name="ProjectView">
|
||||
<navigator proportions="" version="1">
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="PackagesPane" />
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<expand>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="java" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="java" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="core" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="kotlin" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="kotlin" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="influencedht" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="kotlin" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="influencedht" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="core" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="kotlin" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="influencedht" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="core" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="routing" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="main" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="kotlin" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="influencedht" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="core" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="rpc" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="InfluenceDHT" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="test" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="influencedht" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="Scratches and Consoles" type="1a2a3e82:ScratchProjectViewPane$MyProjectNode" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
<pane id="Scope" />
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="com.intellij.ide.scratch.LRUPopupBuilder$1/New Scratch File" value="KND" />
|
||||
<property name="project.structure.last.edited" value="Project" />
|
||||
<property name="project.structure.proportion" value="0.0" />
|
||||
<property name="project.structure.side.proportion" value="0.0" />
|
||||
<property name="settings.editor.selected.configurable" value="fileTemplates" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="MoveKotlinTopLevelDeclarationsDialog.RECENTS_KEY">
|
||||
<recent name="io.github.chronosx88.influencedht.core.rpc" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="a3421dfe-66c3-4c54-8bb2-850502ef6dd2" name="Default Changelist" comment="" />
|
||||
<created>1555921109432</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1555921109432</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="-1" y="-1" width="1922" height="1037" extended-state="6" />
|
||||
<editor active="true" />
|
||||
<layout>
|
||||
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.2550586" />
|
||||
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
||||
<window_info id="Designer" order="2" />
|
||||
<window_info id="UI Designer" order="3" />
|
||||
<window_info id="Favorites" order="4" side_tool="true" />
|
||||
<window_info anchor="bottom" id="Message" order="0" />
|
||||
<window_info anchor="bottom" id="Find" order="1" weight="0.32932165" />
|
||||
<window_info anchor="bottom" id="Run" order="2" />
|
||||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||
<window_info anchor="bottom" id="TODO" order="6" />
|
||||
<window_info anchor="bottom" id="Version Control" order="7" />
|
||||
<window_info anchor="bottom" id="Terminal" order="8" visible="true" weight="0.32932165" />
|
||||
<window_info anchor="bottom" id="Event Log" order="9" sideWeight="0.5005325" side_tool="true" weight="0.32932165" />
|
||||
<window_info anchor="bottom" id="Build" order="10" sideWeight="0.49946752" weight="0.32932165" />
|
||||
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
|
||||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||
<window_info anchor="right" id="Palette" order="3" />
|
||||
<window_info anchor="right" id="Maven" order="4" />
|
||||
<window_info anchor="right" id="Gradle" order="5" />
|
||||
<window_info anchor="right" id="Palette	" order="6" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$APPLICATION_CONFIG_DIR$/consoles/jshell/jshell_console.snippet">
|
||||
<provider selected="true" editor-type-id="text-editor" />
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/gradle.properties">
|
||||
<provider selected="true" editor-type-id="text-editor" />
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/1.kt" />
|
||||
<entry file="file://$APPLICATION_CONFIG_DIR$/scratches/scratch.def">
|
||||
<provider selected="true" editor-type-id="text-editor" />
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/build.gradle">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="51">
|
||||
<caret line="3" column="55" selection-start-line="3" selection-start-column="55" selection-end-line="3" selection-end-column="55" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/settings.gradle">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="34">
|
||||
<caret line="2" lean-forward="true" selection-start-line="2" selection-end-line="2" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/Number.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="119">
|
||||
<caret line="21" column="22" selection-start-line="21" selection-start-column="22" selection-end-line="21" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/KademliaID.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="408">
|
||||
<caret line="116" column="5" selection-start-line="116" selection-start-column="5" selection-end-line="116" selection-end-column="5" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar:///usr/lib/jvm/java-8-jdk/src.zip!/java/awt/image/DataBuffer.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="296">
|
||||
<caret line="69" column="22" selection-start-line="69" selection-start-column="22" selection-end-line="69" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar:///usr/lib/jvm/java-8-jdk/src.zip!/java/nio/ByteBuffer.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-1183">
|
||||
<caret line="261" column="22" selection-start-line="261" selection-start-column="22" selection-end-line="261" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/text/StringsJVM.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="296">
|
||||
<caret line="410" column="25" selection-start-line="410" selection-start-column="25" selection-end-line="410" selection-end-column="25" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar:///usr/lib/jvm/java-8-jdk/src.zip!/java/net/InetSocketAddress.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="595">
|
||||
<caret line="63" column="16" selection-start-line="63" selection-start-column="16" selection-end-line="63" selection-end-column="16" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.3.30/9c981bc2a33066176e605b58a84170b8116e9d8c/kotlin-stdlib-common-1.3.30-sources.jar!/kotlin/collections/Sets.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="296">
|
||||
<caret line="33" column="28" lean-forward="true" selection-start-line="33" selection-start-column="28" selection-end-line="33" selection-end-column="28" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/Collections.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="279">
|
||||
<caret line="255" column="3" lean-forward="true" selection-start-line="255" selection-start-column="3" selection-end-line="255" selection-end-column="3" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/PeerSocketAddress.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="153">
|
||||
<caret line="12" column="6" selection-start-line="12" selection-start-column="6" selection-end-line="12" selection-end-column="6" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/PeerAddress.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="289">
|
||||
<caret line="34" column="6" selection-start-line="34" selection-start-column="6" selection-end-line="34" selection-end-column="6" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar:///usr/lib/jvm/java-8-jdk/src.zip!/java/net/InetAddress.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="296">
|
||||
<caret line="670" column="18" selection-start-line="670" selection-start-column="18" selection-end-line="670" selection-end-column="18" />
|
||||
<folding>
|
||||
<element signature="e#24226#24227#0" expanded="true" />
|
||||
<element signature="e#24253#24254#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/io/IOStreams.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="685">
|
||||
<caret line="133" column="23" selection-start-line="133" selection-start-column="23" selection-end-line="133" selection-end-column="23" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar:///usr/lib/jvm/java-8-jdk/src.zip!/java/io/FilterInputStream.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="296">
|
||||
<caret line="81" column="15" selection-start-line="81" selection-start-column="15" selection-end-line="81" selection-end-column="15" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar:///usr/lib/jvm/java-8-jdk/src.zip!/java/io/DataInputStream.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="755">
|
||||
<caret line="98" column="21" selection-start-line="98" selection-start-column="21" selection-end-line="98" selection-end-column="21" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar:///usr/lib/jvm/java-8-jdk/src.zip!/java/util/Comparator.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-163">
|
||||
<caret line="108" column="17" selection-start-line="108" selection-start-column="17" selection-end-line="108" selection-end-column="17" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar:///usr/lib/jvm/java-8-jdk/src.zip!/javax/print/attribute/IntegerSyntax.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="296">
|
||||
<caret line="44" column="22" selection-start-line="44" selection-start-column="22" selection-end-line="44" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar:///usr/lib/jvm/java-8-jdk/src.zip!/java/lang/Integer.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="296">
|
||||
<caret line="1322" column="36" selection-start-line="1322" selection-start-column="36" selection-end-line="1322" selection-end-column="36" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/Primitives.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="2336">
|
||||
<caret line="649" column="21" selection-start-line="649" selection-start-column="21" selection-end-line="649" selection-end-column="21" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.3.30/9c981bc2a33066176e605b58a84170b8116e9d8c/kotlin-stdlib-common-1.3.30-sources.jar!/kotlin/experimental/bitwiseOperations.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="119">
|
||||
<caret line="10" column="29" selection-start-line="10" selection-start-column="29" selection-end-line="10" selection-end-column="29" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/Any.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="340">
|
||||
<caret line="34" column="29" selection-start-line="34" selection-start-column="29" selection-end-line="34" selection-end-column="29" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/Utils.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="748">
|
||||
<caret line="139" column="5" selection-start-line="139" selection-start-column="5" selection-end-line="139" selection-end-column="5" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/IKadConfiguration.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="748">
|
||||
<caret line="50" column="7" selection-start-line="50" selection-start-column="7" selection-end-line="50" selection-end-column="7" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/DefaultKadConfig.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="170">
|
||||
<caret line="10" column="34" selection-start-line="10" selection-start-column="34" selection-end-line="10" selection-end-column="34" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/jvm/annotations/JvmFlagAnnotations.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="714">
|
||||
<caret line="45" column="31" selection-start-line="45" selection-start-column="31" selection-end-line="45" selection-end-column="31" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/Library.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="296">
|
||||
<caret line="35" column="38" selection-start-line="35" selection-start-column="38" selection-end-line="35" selection-end-column="38" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/Array.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="102">
|
||||
<caret line="9" column="78" selection-start-line="9" selection-start-column="78" selection-end-line="9" selection-end-column="78" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/text/TypeAliases.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="102">
|
||||
<caret line="9" column="33" selection-start-line="9" selection-start-column="27" selection-end-line="9" selection-end-column="33" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/routing/PeerContact.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="255">
|
||||
<caret line="15" column="17" selection-start-line="15" selection-start-column="17" selection-end-line="15" selection-end-column="17" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/routing/KademliaBucket.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="2720">
|
||||
<caret line="160" column="15" selection-start-line="160" selection-start-column="15" selection-end-line="160" selection-end-column="15" />
|
||||
<folding>
|
||||
<element signature="e#56#138#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/java/io/gitub/chronosx88/influencedht/core/Number160.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="2553">
|
||||
<caret line="467" column="51" lean-forward="true" selection-start-line="467" selection-start-column="51" selection-end-line="467" selection-end-column="51" />
|
||||
<folding>
|
||||
<element signature="imports" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/rpc/RPCActions.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="85">
|
||||
<caret line="5" column="10" selection-start-line="5" selection-start-column="10" selection-end-line="5" selection-end-column="10" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/KeyComparator.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="221">
|
||||
<caret line="13" column="66" selection-start-line="13" selection-start-column="66" selection-end-line="13" selection-end-column="66" />
|
||||
<folding>
|
||||
<element signature="e#48#121#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.30/1093224407fb1a6f5b79358044a2836bb3d899fd/kotlin-stdlib-1.3.30-sources.jar!/kotlin/ArrayIntrinsics.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="153">
|
||||
<caret line="23" column="45" selection-start-line="23" selection-start-column="45" selection-end-line="23" selection-end-column="45" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/routing/KademliaRoutingTable.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="476">
|
||||
<caret line="71" column="29" selection-start-line="71" selection-start-column="29" selection-end-line="71" selection-end-column="29" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main/kotlin/io/github/chronosx88/influencedht/core/PeerAddress.kt">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-204">
|
||||
<caret line="44" column="63" selection-start-line="44" selection-start-column="63" selection-end-line="44" selection-end-column="63" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="ArtifactsStructureConfigurable.UI">
|
||||
<settings>
|
||||
<artifact-editor />
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="FacetStructureConfigurable.UI">
|
||||
<settings>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="GlobalLibrariesConfigurable.UI">
|
||||
<settings>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="JdkListConfigurable.UI">
|
||||
<settings>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="ModuleStructureConfigurable.UI">
|
||||
<settings>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="ProjectJDKs.UI">
|
||||
<settings>
|
||||
<last-edited>1.8</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="ProjectLibrariesConfigurable.UI">
|
||||
<settings>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
</states>
|
||||
</component>
|
||||
</project>
|
26
build.gradle
Normal file
26
build.gradle
Normal file
@ -0,0 +1,26 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.3.30'
|
||||
id 'com.github.johnrengelman.shadow' version '4.0.4'
|
||||
}
|
||||
|
||||
group 'io.github.chronosx88'
|
||||
version '0.1'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
1
gradle.properties
Normal file
1
gradle.properties
Normal file
@ -0,0 +1 @@
|
||||
kotlin.code.style=official
|
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 @@
|
||||
#Mon Apr 22 12:19:51 MSK 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip
|
172
gradlew
vendored
Executable file
172
gradlew
vendored
Executable file
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## 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=""
|
||||
|
||||
# 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, switch paths to Windows format before running java
|
||||
if $cygwin ; 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" "$@"
|
84
gradlew.bat
vendored
Normal file
84
gradlew.bat
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
@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=
|
||||
|
||||
@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
|
2
settings.gradle
Normal file
2
settings.gradle
Normal file
@ -0,0 +1,2 @@
|
||||
rootProject.name = 'InfluenceDHT'
|
||||
|
@ -0,0 +1,534 @@
|
||||
package io.gitub.chronosx88.influencedht.core;
|
||||
|
||||
/*
|
||||
* Copyright 2019 Thomas Bocek
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
import io.github.chronosx88.influencedht.core.Utils;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
/**
|
||||
* This class represents a 160 bit number. This class is preferred over BigInteger as we always have 160bit, and thus,
|
||||
* methods can be optimized.
|
||||
*
|
||||
* @author Thomas Bocek
|
||||
*/
|
||||
public final class Number160 extends Number implements Comparable<Number160> {
|
||||
private static final long serialVersionUID = -6386562272459272306L;
|
||||
|
||||
// This key has *always* 160 bit. Do not change.
|
||||
public static final int BITS = 160;
|
||||
|
||||
private static final long LONG_MASK = 0xffffffffL;
|
||||
|
||||
private static final int BYTE_MASK = 0xff;
|
||||
|
||||
private static final int CHAR_MASK = 0xf;
|
||||
|
||||
private static final int STRING_LENGTH = 42;
|
||||
|
||||
// a map used for String <-> Key conversion
|
||||
private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c',
|
||||
'd', 'e', 'f' };
|
||||
|
||||
// size of the backing integer array
|
||||
public static final int INT_ARRAY_SIZE = BITS / Integer.SIZE;
|
||||
|
||||
// size of a byte array
|
||||
public static final int BYTE_ARRAY_SIZE = BITS / Byte.SIZE;
|
||||
|
||||
public static final int CHARS_PER_INT = 8;
|
||||
|
||||
// backing integer array
|
||||
private final int[] val;
|
||||
|
||||
// constants
|
||||
public static final Number160 ZERO = new Number160(0);
|
||||
|
||||
public static final Number160 ONE = new Number160(1);
|
||||
|
||||
public static final Number160 MAX_VALUE = new Number160(new int[] { -1, -1, -1, -1, -1 });
|
||||
|
||||
/**
|
||||
* Create a Key with value 0.
|
||||
*/
|
||||
public Number160() {
|
||||
this.val = new int[INT_ARRAY_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance with an integer array. This integer array will be copied into the backing array.
|
||||
*
|
||||
* @param val
|
||||
* The value to copy to the backing array. Since this class stores 160bit numbers, the array needs to be
|
||||
* of size 5 or smaller.
|
||||
*/
|
||||
public Number160(final int... val) {
|
||||
if (val.length > INT_ARRAY_SIZE) {
|
||||
throw new IllegalArgumentException(String.format("Can only deal with arrays of size smaller or equal to %s. Provided array has %s length.", INT_ARRAY_SIZE, val.length));
|
||||
}
|
||||
this.val = new int[INT_ARRAY_SIZE];
|
||||
final int len = val.length;
|
||||
for (int i = len - 1, j = INT_ARRAY_SIZE - 1; i >= 0; i--, j--) {
|
||||
this.val[j] = val[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Key from a string. The string has to be of length 42 to fit into the backing array. Note that this
|
||||
* string is *always* in hexadecimal, there is no 0x... required before the number.
|
||||
*
|
||||
* @param val
|
||||
* The characters allowed are [0-9a-f], which is in hexadecimal
|
||||
*/
|
||||
public Number160(final String val) {
|
||||
if (val.length() > STRING_LENGTH) {
|
||||
throw new IllegalArgumentException(String.format("Can only deal with strings of size smaller or equal to %s. Provided string has %s length.", STRING_LENGTH, val.length()));
|
||||
}
|
||||
if (val.indexOf("0x") != 0) {
|
||||
throw new IllegalArgumentException(val
|
||||
+ " is not in hexadecimal form. Decimal form is not supported yet");
|
||||
}
|
||||
this.val = new int[INT_ARRAY_SIZE];
|
||||
final char[] tmp = val.toCharArray();
|
||||
final int len = tmp.length;
|
||||
for (int i = STRING_LENGTH - len, j = 2; i < (STRING_LENGTH - 2); i++, j++) {
|
||||
this.val[i >> 3] <<= 4;
|
||||
|
||||
int digit = Character.digit(tmp[j], 16);
|
||||
if (digit < 0) {
|
||||
throw new RuntimeException("Not a hexadecimal number \"" + tmp[j]
|
||||
+ "\". The range is [0-9a-f]");
|
||||
}
|
||||
// += or |= does not matter here
|
||||
this.val[i >> 3] += digit & CHAR_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Key with the integer value.
|
||||
*
|
||||
* @param val
|
||||
* integer value
|
||||
*/
|
||||
public Number160(final int val) {
|
||||
this.val = new int[INT_ARRAY_SIZE];
|
||||
this.val[INT_ARRAY_SIZE - 1] = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Key with the long value.
|
||||
*
|
||||
* @param val
|
||||
* long value
|
||||
*/
|
||||
public Number160(final long val) {
|
||||
this.val = new int[INT_ARRAY_SIZE];
|
||||
this.val[INT_ARRAY_SIZE - 1] = (int) val;
|
||||
this.val[INT_ARRAY_SIZE - 2] = (int) (val >> Integer.SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Key using the byte array. The array is copied to the backing int[]
|
||||
*
|
||||
* @param val
|
||||
* byte array
|
||||
*/
|
||||
public Number160(final byte[] val) {
|
||||
this(val, 0, val.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Key using the byte array. The array is copied to the backing int[] starting at the given offest.
|
||||
*
|
||||
* @param val
|
||||
* byte array
|
||||
* @param offset
|
||||
* The offset where to start
|
||||
* @param length
|
||||
* the length to read
|
||||
*/
|
||||
public Number160(final byte[] val, final int offset, final int length) {
|
||||
if (length > BYTE_ARRAY_SIZE) {
|
||||
throw new IllegalArgumentException(String.format("Can only deal with byte arrays of size smaller or equal to %s. Provided array has %s length.", BYTE_ARRAY_SIZE, length));
|
||||
}
|
||||
this.val = new int[INT_ARRAY_SIZE];
|
||||
for (int i = length + offset - 1, j = BYTE_ARRAY_SIZE - 1, k = 0; i >= offset; i--, j--, k++) {
|
||||
// += or |= does not matter here
|
||||
this.val[j >> 2] |= (val[i] & BYTE_MASK) << ((k % 4) << 3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Key with random values in it.
|
||||
*
|
||||
* @param random
|
||||
* The object to create pseudo random numbers. For testing and debugging, the seed in the random class
|
||||
* can be set to make the random values repeatable.
|
||||
*/
|
||||
public Number160(final Random random) {
|
||||
this.val = new int[INT_ARRAY_SIZE];
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
this.val[i] = random.nextInt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new key with a long for the first 64bits, and using the lower 96bits for the rest.
|
||||
*
|
||||
* @param timestamp
|
||||
* The long value that will be set in the beginning (most significant)
|
||||
* @param number96
|
||||
* The rest will be filled with this number
|
||||
*/
|
||||
public Number160(final long timestamp, Number160 number96) {
|
||||
this.val = new int[INT_ARRAY_SIZE];
|
||||
this.val[0] = (int) (timestamp >> Integer.SIZE);
|
||||
this.val[1] = (int) timestamp;
|
||||
this.val[2] = number96.val[2];
|
||||
this.val[3] = number96.val[3];
|
||||
this.val[4] = number96.val[4];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The first (most significant) 64bits
|
||||
*/
|
||||
public long timestamp() {
|
||||
return ((this.val[0] & LONG_MASK) << Integer.SIZE) + (this.val[1] & LONG_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The lower (least significant) 96 bits
|
||||
*/
|
||||
public Number160 number96() {
|
||||
return new Number160(0, 0, this.val[2], this.val[3], this.val[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Xor operation. This operation is ~2.5 times faster than with BigInteger
|
||||
*
|
||||
* @param key
|
||||
* The second operand for the xor operation
|
||||
* @return A new key with the result of the xor operation
|
||||
*/
|
||||
public Number160 xor(final Number160 key) {
|
||||
final int[] result = new int[INT_ARRAY_SIZE];
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
result[i] = this.val[i] ^ key.val[i];
|
||||
}
|
||||
return new Number160(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the backing array, which is always of size 5.
|
||||
*
|
||||
* @return a copy of the backing array
|
||||
*/
|
||||
public int[] toIntArray() {
|
||||
final int[] retVal = new int[INT_ARRAY_SIZE];
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
retVal[i] = this.val[i];
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the byte array with this number.
|
||||
*
|
||||
* @param me
|
||||
* the byte array
|
||||
* @param offset
|
||||
* where to start in the byte array
|
||||
* @return the offset we have read
|
||||
*/
|
||||
public int toByteArray(final byte[] me, final int offset) {
|
||||
if (offset + BYTE_ARRAY_SIZE > me.length) {
|
||||
throw new RuntimeException("array too small");
|
||||
}
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
// multiply by four
|
||||
final int idx = offset + (i << 2);
|
||||
me[idx + 0] = (byte) (val[i] >> 24);
|
||||
me[idx + 1] = (byte) (val[i] >> 16);
|
||||
me[idx + 2] = (byte) (val[i] >> 8);
|
||||
me[idx + 3] = (byte) (val[i]);
|
||||
}
|
||||
return offset + BYTE_ARRAY_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array, which is always of size 20.
|
||||
*
|
||||
* @return a byte array
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
final byte[] retVal = new byte[BYTE_ARRAY_SIZE];
|
||||
toByteArray(retVal, 0);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the content in a human readable manner.
|
||||
*
|
||||
* @param removeLeadingZero
|
||||
* Indicates if leading zeros should be removed
|
||||
* @return A human readable representation of this key
|
||||
*/
|
||||
public String toString(final boolean removeLeadingZero) {
|
||||
boolean removeZero = removeLeadingZero;
|
||||
final StringBuilder sb = new StringBuilder("0x");
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
toHex(val[i], removeZero, sb);
|
||||
if (removeZero && val[i] != 0) {
|
||||
removeZero = false;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is zero.
|
||||
*
|
||||
* @return True if this number is zero, false otherwise
|
||||
*/
|
||||
public boolean isZero() {
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
if (this.val[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of bits used to represent this number. All leading (leftmost) zero bits are ignored
|
||||
*
|
||||
* @return The bits used
|
||||
*/
|
||||
public int bitLength() {
|
||||
int bits = 0;
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
if (this.val[i] != 0) {
|
||||
bits += Integer.SIZE - Integer.numberOfLeadingZeros(this.val[i]);
|
||||
bits += Integer.SIZE * (INT_ARRAY_SIZE - ++i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
double d = 0;
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
d *= LONG_MASK + 1;
|
||||
d += this.val[i] & LONG_MASK;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return (float) doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
return this.val[INT_ARRAY_SIZE - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* For debugging...
|
||||
*
|
||||
* @param pos
|
||||
* the position in the internal array
|
||||
* @return the long of the unsigned int
|
||||
*/
|
||||
long unsignedInt(final int pos) {
|
||||
return this.val[pos] & LONG_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longValue() {
|
||||
return ((this.val[INT_ARRAY_SIZE - 1] & LONG_MASK) << Integer.SIZE)
|
||||
+ (this.val[INT_ARRAY_SIZE - 2] & LONG_MASK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Number160 o) {
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
long b1 = val[i] & LONG_MASK;
|
||||
long b2 = o.val[i] & LONG_MASK;
|
||||
if (b1 < b2) {
|
||||
return -1;
|
||||
} else if (b1 > b2) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof Number160)) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
final Number160 key = (Number160) obj;
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
if (key.val[i] != val[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 0;
|
||||
for (int i = 0; i < INT_ARRAY_SIZE; i++) {
|
||||
hashCode = (int) (31 * hashCode + (val[i] & LONG_MASK));
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an integer to hex value.
|
||||
*
|
||||
* @param integer2
|
||||
* The integer to convert
|
||||
* @param removeLeadingZero
|
||||
* indicate if leading zeros should be ignored
|
||||
* @param sb
|
||||
* The string builder where to store the result
|
||||
*/
|
||||
private static void toHex(final int integer2, final boolean removeLeadingZero, final StringBuilder sb) {
|
||||
// 4 bits form a char, thus we have 160/4=40 chars in a key, with an
|
||||
// integer array size of 5, this gives 8 chars per integer
|
||||
|
||||
final char[] buf = new char[CHARS_PER_INT];
|
||||
int charPos = CHARS_PER_INT;
|
||||
int integer = integer2;
|
||||
for (int i = 0; i < CHARS_PER_INT && !(removeLeadingZero && integer == 0); i++) {
|
||||
buf[--charPos] = DIGITS[integer & CHAR_MASK];
|
||||
// for hexadecimal, we have 4 bits per char, which ranges from
|
||||
// [0-9a-f]
|
||||
integer >>>= 4;
|
||||
}
|
||||
sb.append(buf, charPos, (CHARS_PER_INT - charPos));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Number160 from the integer, which fills all the 160bits. A new random object will be created.
|
||||
*
|
||||
* @param integerValue
|
||||
* The value to hash from
|
||||
* @return A hash from based on pseudo random, to fill the 160bits
|
||||
*/
|
||||
public static Number160 createHash(final int integerValue) {
|
||||
Random r = new Random(integerValue);
|
||||
return new Number160(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Number160 from the long, which fills all the 160 bits. A new random object will be created, thus, its
|
||||
* thread safe
|
||||
*
|
||||
* @param longValue
|
||||
* The value to hash from (seed)
|
||||
* @return A hash based on pseudo random, to fill the 160bits
|
||||
*/
|
||||
public static Number160 createHash(final long longValue) {
|
||||
Random r = new Random(longValue);
|
||||
return new Number160(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Number160 using SHA1 on the string.
|
||||
*
|
||||
* @param string
|
||||
* The value to hash from
|
||||
* @return A hash based on SHA1 of the string
|
||||
*/
|
||||
public static Number160 createHash(final String string) {
|
||||
return Utils.makeSHAHash(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of leading 0's in this NodeId
|
||||
*
|
||||
* @return Integer The number of leading 0's
|
||||
*/
|
||||
public int getFirstSetBitIndex()
|
||||
{
|
||||
int prefixLength = 0;
|
||||
|
||||
for (byte b : this.toByteArray())
|
||||
{
|
||||
if (b == 0)
|
||||
{
|
||||
prefixLength += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the byte is not 0, we need to count how many MSBs are 0 */
|
||||
int count = 0;
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
boolean a = (b & (1 << i)) == 0;
|
||||
if (a)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // Reset the count if we encounter a non-zero number
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the count of MSB 0s to the prefix length */
|
||||
prefixLength += count;
|
||||
|
||||
/* Break here since we've now covered the MSB 0s */
|
||||
break;
|
||||
}
|
||||
}
|
||||
return prefixLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the distance from this ID to another ID
|
||||
*
|
||||
* @param to
|
||||
*
|
||||
* @return Integer The distance
|
||||
*/
|
||||
public int getDistance(Number160 to)
|
||||
{
|
||||
// Compute the xor of this and to
|
||||
// Get the index i of the first set bit of the xor returned NodeId
|
||||
// The distance between them is ID_LENGTH - i
|
||||
return BITS - this.xor(to).getFirstSetBitIndex();
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package io.github.chronosx88.influencedht.core
|
||||
|
||||
class DefaultKadConfig: IKadConfiguration {
|
||||
private val RESTORE_INTERVAL = (60 * 1000).toLong() // in milliseconds
|
||||
private val RESPONSE_TIMEOUT: Long = 2000
|
||||
private val OPERATION_TIMEOUT: Long = 2000
|
||||
private val CONCURRENCY = 10
|
||||
private val K = 5
|
||||
private val RCSIZE = 3
|
||||
private val STALE = 1
|
||||
private val IS_TESTING = false
|
||||
|
||||
override val isTesting: Boolean
|
||||
get() = IS_TESTING
|
||||
override val restoreInterval: Long
|
||||
get() = RESTORE_INTERVAL
|
||||
override val responseTimeout: Long
|
||||
get() = RESPONSE_TIMEOUT
|
||||
override val operationTimeout: Long
|
||||
get() = OPERATION_TIMEOUT
|
||||
override val maxConcurrentMessagesTransiting: Int
|
||||
get() = CONCURRENCY
|
||||
override val k: Int
|
||||
get() = K
|
||||
override val replacementCacheSize: Int
|
||||
get() = RCSIZE
|
||||
override val stale: Int
|
||||
get() = STALE
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package io.github.chronosx88.influencedht.core
|
||||
|
||||
/**
|
||||
* Interface that defines a IKadConfiguration object
|
||||
*
|
||||
* @author Joshua Kissoon
|
||||
*/
|
||||
interface IKadConfiguration {
|
||||
|
||||
/**
|
||||
* @return Whether we're in a testing or production system.
|
||||
*/
|
||||
val isTesting: Boolean
|
||||
|
||||
/**
|
||||
* @return Interval in milliseconds between execution of RestoreOperations.
|
||||
*/
|
||||
val restoreInterval: Long
|
||||
|
||||
/**
|
||||
* If no reply received from a node in this period (in milliseconds)
|
||||
* consider the node unresponsive.
|
||||
*
|
||||
* @return The time it takes to consider a node unresponsive
|
||||
*/
|
||||
val responseTimeout: Long
|
||||
|
||||
/**
|
||||
* @return Maximum number of milliseconds for performing an operation.
|
||||
*/
|
||||
val operationTimeout: Long
|
||||
|
||||
/**
|
||||
* @return Maximum number of concurrent messages in transit.
|
||||
*/
|
||||
val maxConcurrentMessagesTransiting: Int
|
||||
|
||||
/**
|
||||
* @return K-Value used throughout Kademlia
|
||||
*/
|
||||
val k: Int
|
||||
|
||||
/**
|
||||
* @return Size of replacement cache.
|
||||
*/
|
||||
val replacementCacheSize: Int
|
||||
|
||||
/**
|
||||
* @return # of times a node can be marked as stale before it is actually removed.
|
||||
*/
|
||||
val stale: Int
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package io.github.chronosx88.influencedht.core
|
||||
|
||||
import io.gitub.chronosx88.influencedht.core.Number160
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A Comparator to compare 2 keys to a given key
|
||||
*
|
||||
* @author Joshua Kissoon
|
||||
*/
|
||||
class KeyComparator(private val key: Number160): Comparator<PeerAddress> {
|
||||
|
||||
/**
|
||||
* Compare two objects which must both be of type `PeerAddress`
|
||||
* and determine which is closest to the identifier specified in the
|
||||
* constructor.
|
||||
*
|
||||
* @param n1 Node 1 to compare distance from the key
|
||||
* @param n2 Node 2 to compare distance from the key
|
||||
*/
|
||||
override fun compare(n1: PeerAddress, n2: PeerAddress): Int {
|
||||
var b1 = n1.nodeId
|
||||
var b2 = n2.nodeId
|
||||
|
||||
b1 = b1!!.xor(key)
|
||||
b2 = b2!!.xor(key)
|
||||
|
||||
return b1.compareTo(b2)
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package io.github.chronosx88.influencedht.core
|
||||
|
||||
import io.gitub.chronosx88.influencedht.core.Number160
|
||||
import java.io.DataInputStream
|
||||
import java.io.DataOutputStream
|
||||
import java.io.IOException
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.net.InetAddress
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
/**
|
||||
* A PeerAddress in the Kademlia network - Contains basic node network information.
|
||||
*
|
||||
* @author Joshua Kissoon
|
||||
*/
|
||||
class PeerAddress {
|
||||
|
||||
/**
|
||||
* @return The NodeId object of this node
|
||||
*/
|
||||
var nodeId: Number160? = null
|
||||
private set
|
||||
private var inetAddress: InetAddress? = null
|
||||
private var port: Int = 0
|
||||
private val strRep: String
|
||||
|
||||
/**
|
||||
* Creates a SocketAddress for this node
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
val socketAddress: InetSocketAddress
|
||||
get() = InetSocketAddress(this.inetAddress, this.port)
|
||||
|
||||
constructor(nid: Number160, ip: InetAddress, port: Int) {
|
||||
this.nodeId = nid
|
||||
this.inetAddress = ip
|
||||
this.port = port
|
||||
this.strRep = this.nodeId!!.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the PeerAddress's data from a DataInput stream
|
||||
*
|
||||
* @param inputStream Stream which contains this PeerAddress
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
constructor(inputStream: DataInputStream) {
|
||||
this.fromStream(inputStream)
|
||||
this.strRep = this.nodeId!!.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the InetAddress of this node
|
||||
*
|
||||
* @param addr The new InetAddress of this node
|
||||
*/
|
||||
fun setInetAddress(addr: InetAddress) {
|
||||
this.inetAddress = addr
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun toStream(out: DataOutputStream) {
|
||||
/* Add the NodeId to the stream */
|
||||
out.write(this.nodeId!!.toByteArray())
|
||||
|
||||
/* Add the PeerAddress's IP address to the stream */
|
||||
val a = inetAddress!!.address
|
||||
if (a.size != 4) {
|
||||
throw IllegalArgumentException("Expected InetAddress of 4 bytes, got " + a.size)
|
||||
}
|
||||
out.write(a)
|
||||
|
||||
/* Add the port to the stream */
|
||||
out.writeInt(port)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun fromStream(inputStream: DataInputStream) {
|
||||
/* Load the NodeId */
|
||||
val nodeIDBinary = ByteArray(Number160.BYTE_ARRAY_SIZE)
|
||||
inputStream.readFully(nodeIDBinary)
|
||||
this.nodeId = Number160(nodeIDBinary)
|
||||
/* Load the IP Address */
|
||||
val ip = ByteArray(4)
|
||||
inputStream.readFully(ip)
|
||||
this.inetAddress = InetAddress.getByAddress(ip)
|
||||
|
||||
/* Read inputStream the port */
|
||||
this.port = inputStream.readInt()
|
||||
}
|
||||
|
||||
override fun equals(o: Any?): Boolean {
|
||||
if (o is PeerAddress) {
|
||||
val n = o as PeerAddress?
|
||||
return if (n === this) {
|
||||
true
|
||||
} else this.nodeId!!.equals(n!!.nodeId)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return this.nodeId!!.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return this.nodeId!!.toString()
|
||||
}
|
||||
}
|
141
src/main/kotlin/io/github/chronosx88/influencedht/core/Utils.kt
Normal file
141
src/main/kotlin/io/github/chronosx88/influencedht/core/Utils.kt
Normal file
@ -0,0 +1,141 @@
|
||||
package io.github.chronosx88.influencedht.core
|
||||
|
||||
import io.gitub.chronosx88.influencedht.core.Number160
|
||||
import java.net.Inet4Address
|
||||
import java.net.Inet6Address
|
||||
import java.net.InetAddress
|
||||
import java.net.UnknownHostException
|
||||
import java.nio.ByteBuffer
|
||||
import java.security.MessageDigest
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.util.*
|
||||
import kotlin.experimental.and
|
||||
|
||||
object Utils {
|
||||
const val IPV4_BYTES = 4
|
||||
const val IPV6_BYTES = 16
|
||||
const val BYTE_BITS = 8
|
||||
const val MASK_0F = 0xf // 00000000 00000000 00000000 00001111
|
||||
const val MASK_80 = 0x80 // 00000000 00000000 00000000 10000000
|
||||
const val MASK_FF = 0xff // 00000000 00000000 00000000 11111111
|
||||
const val BYTE_BYTE_SIZE = 1 // 8 bits
|
||||
const val SHORT_BYTE_SIZE = 2 // 16 bits
|
||||
const val INTEGER_BYTE_SIZE = 4 // 32 bits
|
||||
const val LONG_BYTE_SIZE = 8 // 64 bits
|
||||
val EMPTY_BYTE_ARRAY = ByteArray(0)
|
||||
|
||||
@JvmStatic
|
||||
fun makeSHAHash(strInput: String): Number160 {
|
||||
val buffer = strInput.toByteArray()
|
||||
return makeSHAHash(buffer)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun makeSHAHash(buffer: ByteBuffer): Number160 {
|
||||
try {
|
||||
val md = MessageDigest.getInstance("SHA-1")
|
||||
md.update(buffer)
|
||||
val digest = md.digest()
|
||||
return Number160(digest)
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
e.printStackTrace()
|
||||
return Number160()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun makeSHAHash(buffer: ByteArray): Number160 {
|
||||
return makeSHAHash(ByteBuffer.wrap(buffer))
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array to a Inet4Address.
|
||||
*
|
||||
* @param src
|
||||
* the byte array
|
||||
* @param offset
|
||||
* where to start in the byte array
|
||||
* @return The Inet4Address
|
||||
*
|
||||
* @exception IndexOutOfBoundsException
|
||||
* if copying would cause access of data outside array bounds for `src`.
|
||||
* @exception NullPointerException
|
||||
* if either `src` is `null`.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun inet4FromBytes(src: ByteArray, offset: Int): InetAddress {
|
||||
// IPv4 is 32 bit
|
||||
val tmp2 = ByteArray(Utils.IPV4_BYTES)
|
||||
System.arraycopy(src, offset, tmp2, 0, Utils.IPV4_BYTES)
|
||||
try {
|
||||
return Inet4Address.getByAddress(tmp2)
|
||||
} catch (e: UnknownHostException) {
|
||||
/*
|
||||
* This really shouldn't happen in practice since all our byte sequences have the right length. However
|
||||
* {@link InetAddress#getByAddress} is documented as potentially throwing this
|
||||
* "if IP address is of illegal length".
|
||||
*/
|
||||
throw IllegalArgumentException(
|
||||
String.format(
|
||||
"Host address '%s' is not a valid IPv4 address.", Arrays.toString(tmp2)
|
||||
), e
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array to a Inet6Address.
|
||||
*
|
||||
* @param me
|
||||
* me the byte array
|
||||
* @param offset
|
||||
* where to start in the byte array
|
||||
* @return The Inet6Address
|
||||
*
|
||||
* @exception IndexOutOfBoundsException
|
||||
* if copying would cause access of data outside array bounds for `src`.
|
||||
* @exception NullPointerException
|
||||
* if either `src` is `null`.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun inet6FromBytes(me: ByteArray, offset: Int): InetAddress {
|
||||
// IPv6 is 128 bit
|
||||
val tmp2 = ByteArray(Utils.IPV6_BYTES)
|
||||
System.arraycopy(me, offset, tmp2, 0, Utils.IPV6_BYTES)
|
||||
try {
|
||||
return Inet6Address.getByAddress(tmp2)
|
||||
} catch (e: UnknownHostException) {
|
||||
/*
|
||||
* This really shouldn't happen in practice since all our byte sequences have the right length. However
|
||||
* {@link InetAddress#getByAddress} is documented as potentially throwing this
|
||||
* "if IP address is of illegal length".
|
||||
*/
|
||||
throw IllegalArgumentException(
|
||||
String.format(
|
||||
"Host address '%s' is not a valid IPv4 address.", Arrays.toString(tmp2)
|
||||
), e
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a byte to a bit set. BitSet.valueOf(new byte[] {b}) is only available in 1.7, so we need to do this on
|
||||
* our own.
|
||||
*
|
||||
* @param b
|
||||
* The byte to be converted
|
||||
* @return The resulting bit set
|
||||
*/
|
||||
@JvmStatic
|
||||
fun createBitSet(b: Byte): BitSet {
|
||||
val bitSet = BitSet(8)
|
||||
for (i in 0 until Utils.BYTE_BITS) {
|
||||
val value = b and (1 shl i).toByte()
|
||||
bitSet.set(i, value.toInt() != 0)
|
||||
}
|
||||
return bitSet
|
||||
}
|
||||
}
|
@ -0,0 +1,203 @@
|
||||
package io.github.chronosx88.influencedht.core.routing
|
||||
|
||||
import io.github.chronosx88.influencedht.core.IKadConfiguration
|
||||
import io.github.chronosx88.influencedht.core.PeerAddress
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A bucket in the Kademlia routing table
|
||||
*
|
||||
* @property depth How deep is this bucket in the Routing Table
|
||||
* @property config Kademlia configuration
|
||||
*
|
||||
* @author Joshua Kissoon
|
||||
*/
|
||||
class KademliaBucket(@get:Synchronized val depth: Int, private val config: IKadConfiguration) {
|
||||
|
||||
/* Contacts stored in this routing table */
|
||||
private val contacts: TreeSet<PeerContact> = TreeSet()
|
||||
|
||||
/* A set of last seen contacts that can replace any current contact that is unresponsive */
|
||||
private val replacementCache: TreeSet<PeerContact> = TreeSet()
|
||||
|
||||
@Synchronized
|
||||
fun insert(c: PeerContact) {
|
||||
if (this.contacts.contains(c)) {
|
||||
/**
|
||||
* If the contact is already in the bucket, lets update that we've seen it
|
||||
* We need to remove and re-add the contact to get the Sorted Set to update sort order
|
||||
*/
|
||||
val tmp = this.removeFromContacts(c.getPeerAddress())
|
||||
tmp.setSeenNow()
|
||||
tmp.resetStaleCount()
|
||||
this.contacts.add(tmp)
|
||||
} else {
|
||||
/* If the bucket is filled, so put the contacts in the replacement cache */
|
||||
if (contacts.size >= this.config.k) {
|
||||
/* If the cache is empty, we check if any contacts are stale and replace the stalest one */
|
||||
var stalest: PeerContact? = null
|
||||
for (tmp in this.contacts) {
|
||||
if (tmp.staleCount() >= this.config.stale) {
|
||||
/* Contact is stale */
|
||||
if (stalest == null) {
|
||||
stalest = tmp
|
||||
} else if (tmp.staleCount() > stalest.staleCount()) {
|
||||
stalest = tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a stale contact, remove it and add the new contact to the bucket */
|
||||
if (stalest != null) {
|
||||
this.contacts.remove(stalest)
|
||||
this.contacts.add(c)
|
||||
} else {
|
||||
/* No stale contact, lets insert this into replacement cache */
|
||||
this.insertIntoReplacementCache(c)
|
||||
}
|
||||
} else {
|
||||
this.contacts.add(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun insert(n: PeerAddress) {
|
||||
this.insert(PeerContact(n))
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun containsContact(c: PeerContact): Boolean {
|
||||
return this.contacts.contains(c)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun containsNode(n: PeerAddress): Boolean {
|
||||
return this.containsContact(PeerContact(n))
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun removeContact(c: PeerContact): Boolean {
|
||||
/* If the contact does not exist, then we failed to remove it */
|
||||
if (!this.contacts.contains(c)) {
|
||||
return false
|
||||
}
|
||||
|
||||
/* Contact exist, lets remove it only if our replacement cache has a replacement */
|
||||
if (!this.replacementCache.isEmpty()) {
|
||||
/* Replace the contact with one from the replacement cache */
|
||||
this.contacts.remove(c)
|
||||
val replacement = this.replacementCache.first()
|
||||
this.contacts.add(replacement)
|
||||
this.replacementCache.remove(replacement)
|
||||
} else {
|
||||
/* There is no replacement, just increment the contact's stale count */
|
||||
this.getFromContacts(c.getPeerAddress()).incrementStaleCount()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun getFromContacts(n: PeerAddress): PeerContact {
|
||||
for (c in this.contacts) {
|
||||
if (c.getPeerAddress().equals(n)) {
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
/* This contact does not exist */
|
||||
throw NoSuchElementException("The contact does not exist in the contacts list.")
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun removeFromContacts(n: PeerAddress): PeerContact {
|
||||
for (c in this.contacts) {
|
||||
if (c.getPeerAddress().equals(n)) {
|
||||
this.contacts.remove(c)
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
/* We got here means this element does not exist */
|
||||
throw NoSuchElementException("Node does not exist in the replacement cache. ")
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun removeNode(n: PeerAddress): Boolean {
|
||||
return this.removeContact(PeerContact(n))
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun numContacts(): Int {
|
||||
return this.contacts.size
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun getContacts(): List<PeerContact> {
|
||||
val ret = ArrayList<PeerContact>()
|
||||
|
||||
/* If we have no contacts, return the blank arraylist */
|
||||
if (this.contacts.isEmpty()) {
|
||||
return ret
|
||||
}
|
||||
|
||||
/* We have contacts, lets copy put them into the arraylist and return */
|
||||
for (c in this.contacts) {
|
||||
ret.add(c)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* When the bucket is filled, we keep extra contacts in the replacement cache.
|
||||
*/
|
||||
@Synchronized
|
||||
private fun insertIntoReplacementCache(c: PeerContact) {
|
||||
/* Just return if this contact is already in our replacement cache */
|
||||
if (this.replacementCache.contains(c)) {
|
||||
// If the contact is already in the bucket, lets update that we've seen it
|
||||
// We need to remove and re-add the contact to get the Sorted Set to update sort order
|
||||
val tmp = this.removeFromReplacementCache(c.getPeerAddress())
|
||||
tmp.setSeenNow()
|
||||
this.replacementCache.add(tmp)
|
||||
} else if (this.replacementCache.size > this.config.k) {
|
||||
/* if our cache is filled, we remove the least recently seen contact */
|
||||
this.replacementCache.remove(this.replacementCache.last())
|
||||
this.replacementCache.add(c)
|
||||
} else {
|
||||
this.replacementCache.add(c)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun removeFromReplacementCache(n: PeerAddress): PeerContact {
|
||||
for (c in this.replacementCache) {
|
||||
if (c.getPeerAddress().equals(n)) {
|
||||
this.replacementCache.remove(c)
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
/* We got here means this element does not exist */
|
||||
throw NoSuchElementException("Node does not exist in the replacement cache. ")
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun toString(): String {
|
||||
val sb = StringBuilder("Bucket at depth: ")
|
||||
sb.append(this.depth)
|
||||
sb.append("\n Nodes: \n")
|
||||
for (n in this.contacts) {
|
||||
sb.append("Node: ")
|
||||
sb.append(n.getPeerAddress().nodeId.toString())
|
||||
sb.append(" (stale: ")
|
||||
sb.append(n.staleCount())
|
||||
sb.append(")")
|
||||
sb.append("\n")
|
||||
}
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
package io.github.chronosx88.influencedht.core.routing
|
||||
|
||||
import io.github.chronosx88.influencedht.core.IKadConfiguration
|
||||
import io.github.chronosx88.influencedht.core.KeyComparator
|
||||
import io.github.chronosx88.influencedht.core.PeerAddress
|
||||
import io.gitub.chronosx88.influencedht.core.Number160
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Implementation of a Kademlia routing table
|
||||
*
|
||||
* @author Joshua Kissoon
|
||||
*/
|
||||
class KademliaRoutingTable(
|
||||
private val localNode: PeerAddress// The current node
|
||||
, @field:Transient private var config: IKadConfiguration
|
||||
) {
|
||||
/**
|
||||
* @return Bucket[] The buckets in this Kad Instance
|
||||
*/
|
||||
/**
|
||||
* Set the KadBuckets of this routing table, mainly used when retrieving saved state
|
||||
*
|
||||
* @param buckets
|
||||
*/
|
||||
@Transient
|
||||
lateinit var buckets: Array<KademliaBucket>
|
||||
|
||||
/**
|
||||
* @return List A List of all Nodes in this KademliaRoutingTable
|
||||
*/
|
||||
val allNodes: List<PeerAddress>
|
||||
@Synchronized get() {
|
||||
val nodes = ArrayList<PeerAddress>()
|
||||
|
||||
for (b in this.buckets!!) {
|
||||
for (c in b.getContacts()) {
|
||||
nodes.add(c.getPeerAddress())
|
||||
}
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List A List of all Nodes in this KademliaRoutingTable
|
||||
*/
|
||||
val allContacts: List<PeerContact>
|
||||
get() {
|
||||
val contacts = ArrayList<PeerContact>()
|
||||
|
||||
for (b in this.buckets!!) {
|
||||
contacts.addAll(b.getContacts())
|
||||
}
|
||||
|
||||
return contacts
|
||||
}
|
||||
|
||||
init {
|
||||
|
||||
/* Initialize all of the buckets to a specific depth */
|
||||
this.initialize()
|
||||
|
||||
/* Insert the local node */
|
||||
this.insert(localNode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the KademliaRoutingTable to it's default state
|
||||
*/
|
||||
fun initialize() {
|
||||
this.buckets = emptyArray()
|
||||
for (i in 0 until Number160.BITS) {
|
||||
buckets[i] = KademliaBucket(i, this.config)
|
||||
}
|
||||
}
|
||||
|
||||
fun setConfiguration(config: IKadConfiguration) {
|
||||
this.config = config
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a contact to the routing table based on how far it is from the LocalNode.
|
||||
*
|
||||
* @param c The contact to add
|
||||
*/
|
||||
@Synchronized
|
||||
fun insert(c: PeerContact) {
|
||||
this.buckets!![this.getBucketId(c.getPeerAddress().nodeId)].insert(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a node to the routing table based on how far it is from the LocalNode.
|
||||
*
|
||||
* @param n The node to add
|
||||
*/
|
||||
@Synchronized
|
||||
fun insert(n: PeerAddress) {
|
||||
this.buckets!![this.getBucketId(n.nodeId)].insert(n)
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the bucket ID in which a given node should be placed; the bucketId is computed based on how far the node is away from the Local PeerAddress.
|
||||
*
|
||||
* @param nid The NodeId for which we want to find which bucket it belong to
|
||||
*
|
||||
* @return Integer The bucket ID in which the given node should be placed.
|
||||
*/
|
||||
fun getBucketId(nid: Number160?): Int {
|
||||
val bId = this.localNode.nodeId!!.xor(nid).bitLength() - 1
|
||||
|
||||
/* If we are trying to insert a node into it's own routing table, then the bucket ID will be -1, so let's just keep it in bucket 0 */
|
||||
return if (bId < 0) 0 else bId
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the closest set of contacts to a given NodeId
|
||||
*
|
||||
* @param target The NodeId to find contacts close to
|
||||
* @param numNodesRequired The number of contacts to find
|
||||
*
|
||||
* @return List A List of contacts closest to target
|
||||
*/
|
||||
@Synchronized
|
||||
fun findClosest(target: Number160, numNodesRequired: Int): List<PeerAddress> {
|
||||
val sortedSet = TreeSet(KeyComparator(target))
|
||||
sortedSet.addAll(this.allNodes)
|
||||
|
||||
val closest = ArrayList<PeerAddress>(numNodesRequired)
|
||||
|
||||
/* Now we have the sorted set, lets get the top numRequired */
|
||||
var count = 0
|
||||
for (n in sortedSet) {
|
||||
closest.add(n)
|
||||
if (++count == numNodesRequired) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return closest
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used by operations to notify the routing table of any contacts that have been unresponsive.
|
||||
*
|
||||
* @param contacts The set of unresponsive contacts
|
||||
*/
|
||||
fun setUnresponsiveContacts(contacts: List<PeerAddress>) {
|
||||
if (contacts.isEmpty()) {
|
||||
return
|
||||
}
|
||||
for (n in contacts) {
|
||||
this.setUnresponsiveContact(n)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used by operations to notify the routing table of any contacts that have been unresponsive.
|
||||
*
|
||||
* @param n
|
||||
*/
|
||||
@Synchronized
|
||||
fun setUnresponsiveContact(n: PeerAddress) {
|
||||
val bucketId = this.getBucketId(n.nodeId)
|
||||
|
||||
/* Remove the contact from the bucket */
|
||||
this.buckets!![bucketId].removeNode(n)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun toString(): String {
|
||||
val sb = StringBuilder("\n ***************** \n")
|
||||
var totalContacts = 0
|
||||
for (b in this.buckets!!) {
|
||||
if (b.numContacts() > 0) {
|
||||
totalContacts += b.numContacts()
|
||||
sb.append("# nodes in Bucket with depth ")
|
||||
sb.append(b.depth)
|
||||
sb.append(": ")
|
||||
sb.append(b.numContacts())
|
||||
sb.append("\n")
|
||||
sb.append(b.toString())
|
||||
sb.append("\n")
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\nTotal Contacts: ")
|
||||
sb.append(totalContacts)
|
||||
sb.append("\n\n")
|
||||
|
||||
sb.append(" ******************** ")
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package io.github.chronosx88.influencedht.core.routing
|
||||
|
||||
import io.github.chronosx88.influencedht.core.PeerAddress
|
||||
|
||||
/**
|
||||
* Keeps information about contacts of the Node; Contacts are stored in the Buckets in the Routing Table.
|
||||
*
|
||||
* Contacts are used instead of nodes because more information is needed than just the node information.
|
||||
* - Information such as
|
||||
* -- Last seen time
|
||||
*
|
||||
* @author Joshua Kissoon
|
||||
* @since 20140425
|
||||
* @updated 20140426
|
||||
*/
|
||||
class PeerContact(peerAddress: PeerAddress): Comparable<PeerContact> {
|
||||
|
||||
private val n: PeerAddress = peerAddress
|
||||
private var lastSeen: Long = 0
|
||||
|
||||
/**
|
||||
* Stale as described by Kademlia paper page 64
|
||||
* When a contact fails to respond, if the replacement cache is empty and there is no replacement for the contact,
|
||||
* just mark it as stale.
|
||||
*
|
||||
* Now when a new contact is added, if the contact is stale, it is removed.
|
||||
*/
|
||||
private var staleCount: Int = 0
|
||||
|
||||
/**
|
||||
* Create a contact object
|
||||
*
|
||||
* @param n The node associated with this contact
|
||||
*/
|
||||
init {
|
||||
this.lastSeen = System.currentTimeMillis() / 1000L
|
||||
}
|
||||
|
||||
fun getPeerAddress(): PeerAddress {
|
||||
return this.n
|
||||
}
|
||||
|
||||
/**
|
||||
* When a Node sees a contact a gain, the Node will want to update that it's seen recently,
|
||||
* this method updates the last seen timestamp for this contact.
|
||||
*/
|
||||
fun setSeenNow() {
|
||||
this.lastSeen = System.currentTimeMillis() / 1000L
|
||||
}
|
||||
|
||||
/**
|
||||
* When last was this contact seen?
|
||||
*
|
||||
* @return long The last time this contact was seen.
|
||||
*/
|
||||
fun lastSeen(): Long {
|
||||
return this.lastSeen
|
||||
}
|
||||
|
||||
override fun equals(c: Any?): Boolean {
|
||||
return (c as? PeerContact)?.getPeerAddress()?.equals(this.getPeerAddress()) ?: false
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the amount of times this count has failed to respond to a request.
|
||||
*/
|
||||
fun incrementStaleCount() {
|
||||
staleCount++
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Integer Stale count
|
||||
*/
|
||||
fun staleCount(): Int {
|
||||
return this.staleCount
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the stale count of the contact if it's recently seen
|
||||
*/
|
||||
fun resetStaleCount() {
|
||||
this.staleCount = 0
|
||||
}
|
||||
|
||||
override fun compareTo(o: PeerContact): Int {
|
||||
if (this.getPeerAddress().equals(o.getPeerAddress())) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return if (this.lastSeen() > o.lastSeen()) 1 else -1
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return this.getPeerAddress().hashCode()
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package io.github.chronosx88.influencedht.core.rpc
|
||||
|
||||
enum class RPCActions {
|
||||
PUT,
|
||||
GET,
|
||||
REMOVE
|
||||
}
|
Loading…
Reference in New Issue
Block a user