mirror of
https://github.com/ChronosX88/InfluenceDHT-Kotlin.git
synced 2024-12-05 00:02:19 +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