diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9f0962fc4ecc032115c20ad60520ab737301fc42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,66 @@ +/coverage/ +/bin/ + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..985330095c981ebaca9e8891b9b64cc8de30088f --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,29 @@ +image: golang:1.16-buster + +cache: + paths: + - /apt-cache + - /go/src/github.com + - /go/src/golang.org + - /go/src/google.golang.org + - /go/src/gopkg.in + +stages: + - test + - build + +before_script: + - go get -u golang.org/x/lint/golint + +lint_code: + stage: test + script: + - make lint + only: + - merge_requests + +build: + stage: test + script: + - make build + diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..73f69e0958611ac6e00bde95641f6699030ad235 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/aws.xml b/.idea/aws.xml new file mode 100644 index 0000000000000000000000000000000000000000..ec328d0bbf68db9e7322932181cc811412e3ca87 --- /dev/null +++ b/.idea/aws.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="accountSettings"> + <option name="activeProfile" value="profile:default" /> + <option name="activeRegion" value="eu-west-1" /> + <option name="recentlyUsedProfiles"> + <list> + <option value="profile:default" /> + </list> + </option> + <option name="recentlyUsedRegions"> + <list> + <option value="eu-west-1" /> + </list> + </option> + </component> +</project> \ No newline at end of file diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml new file mode 100644 index 0000000000000000000000000000000000000000..ea639c3e6909c3231f0285933b4f83a0e2e69c6d --- /dev/null +++ b/.idea/dbnavigator.xml @@ -0,0 +1,463 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="DBNavigator.Project.DataEditorManager"> + <record-view-column-sorting-type value="BY_INDEX" /> + <value-preview-text-wrapping value="true" /> + <value-preview-pinned value="false" /> + </component> + <component name="DBNavigator.Project.DataExportManager"> + <export-instructions> + <create-header value="true" /> + <friendly-headers value="false" /> + <quote-values-containing-separator value="true" /> + <quote-all-values value="false" /> + <value-separator value="" /> + <file-name value="" /> + <file-location value="" /> + <scope value="GLOBAL" /> + <destination value="FILE" /> + <format value="EXCEL" /> + <charset value="UTF-8" /> + </export-instructions> + </component> + <component name="DBNavigator.Project.DatabaseBrowserManager"> + <autoscroll-to-editor value="false" /> + <autoscroll-from-editor value="true" /> + <show-object-properties value="true" /> + <loaded-nodes /> + </component> + <component name="DBNavigator.Project.DatabaseFileManager"> + <open-files /> + </component> + <component name="DBNavigator.Project.EditorStateManager"> + <last-used-providers /> + </component> + <component name="DBNavigator.Project.ExecutionManager"> + <retain-sticky-names value="false" /> + </component> + <component name="DBNavigator.Project.MethodExecutionManager"> + <method-browser /> + <execution-history> + <group-entries value="true" /> + <execution-inputs /> + </execution-history> + <argument-values-cache /> + </component> + <component name="DBNavigator.Project.ObjectDependencyManager"> + <last-used-dependency-type value="INCOMING" /> + </component> + <component name="DBNavigator.Project.ObjectQuickFilterManager"> + <last-used-operator value="EQUAL" /> + <filters /> + </component> + <component name="DBNavigator.Project.ScriptExecutionManager" clear-outputs="true"> + <recently-used-interfaces /> + </component> + <component name="DBNavigator.Project.Settings"> + <connections /> + <browser-settings> + <general> + <display-mode value="TABBED" /> + <navigation-history-size value="100" /> + <show-object-details value="false" /> + </general> + <filters> + <object-type-filter> + <object-type name="SCHEMA" enabled="true" /> + <object-type name="USER" enabled="true" /> + <object-type name="ROLE" enabled="true" /> + <object-type name="PRIVILEGE" enabled="true" /> + <object-type name="CHARSET" enabled="true" /> + <object-type name="TABLE" enabled="true" /> + <object-type name="VIEW" enabled="true" /> + <object-type name="MATERIALIZED_VIEW" enabled="true" /> + <object-type name="NESTED_TABLE" enabled="true" /> + <object-type name="COLUMN" enabled="true" /> + <object-type name="INDEX" enabled="true" /> + <object-type name="CONSTRAINT" enabled="true" /> + <object-type name="DATASET_TRIGGER" enabled="true" /> + <object-type name="DATABASE_TRIGGER" enabled="true" /> + <object-type name="SYNONYM" enabled="true" /> + <object-type name="SEQUENCE" enabled="true" /> + <object-type name="PROCEDURE" enabled="true" /> + <object-type name="FUNCTION" enabled="true" /> + <object-type name="PACKAGE" enabled="true" /> + <object-type name="TYPE" enabled="true" /> + <object-type name="TYPE_ATTRIBUTE" enabled="true" /> + <object-type name="ARGUMENT" enabled="true" /> + <object-type name="DIMENSION" enabled="true" /> + <object-type name="CLUSTER" enabled="true" /> + <object-type name="DBLINK" enabled="true" /> + </object-type-filter> + </filters> + <sorting> + <object-type name="COLUMN" sorting-type="NAME" /> + <object-type name="FUNCTION" sorting-type="NAME" /> + <object-type name="PROCEDURE" sorting-type="NAME" /> + <object-type name="ARGUMENT" sorting-type="POSITION" /> + </sorting> + <default-editors> + <object-type name="VIEW" editor-type="SELECTION" /> + <object-type name="PACKAGE" editor-type="SELECTION" /> + <object-type name="TYPE" editor-type="SELECTION" /> + </default-editors> + </browser-settings> + <navigation-settings> + <lookup-filters> + <lookup-objects> + <object-type name="SCHEMA" enabled="true" /> + <object-type name="USER" enabled="false" /> + <object-type name="ROLE" enabled="false" /> + <object-type name="PRIVILEGE" enabled="false" /> + <object-type name="CHARSET" enabled="false" /> + <object-type name="TABLE" enabled="true" /> + <object-type name="VIEW" enabled="true" /> + <object-type name="MATERIALIZED VIEW" enabled="true" /> + <object-type name="INDEX" enabled="true" /> + <object-type name="CONSTRAINT" enabled="true" /> + <object-type name="DATASET TRIGGER" enabled="true" /> + <object-type name="DATABASE TRIGGER" enabled="true" /> + <object-type name="SYNONYM" enabled="false" /> + <object-type name="SEQUENCE" enabled="true" /> + <object-type name="PROCEDURE" enabled="true" /> + <object-type name="FUNCTION" enabled="true" /> + <object-type name="PACKAGE" enabled="true" /> + <object-type name="TYPE" enabled="true" /> + <object-type name="DIMENSION" enabled="false" /> + <object-type name="CLUSTER" enabled="false" /> + <object-type name="DBLINK" enabled="true" /> + </lookup-objects> + <force-database-load value="false" /> + <prompt-connection-selection value="true" /> + <prompt-schema-selection value="true" /> + </lookup-filters> + </navigation-settings> + <dataset-grid-settings> + <general> + <enable-zooming value="true" /> + <enable-column-tooltip value="true" /> + </general> + <sorting> + <nulls-first value="true" /> + <max-sorting-columns value="4" /> + </sorting> + <tracking-columns> + <columnNames value="" /> + <visible value="true" /> + <editable value="false" /> + </tracking-columns> + </dataset-grid-settings> + <dataset-editor-settings> + <text-editor-popup> + <active value="false" /> + <active-if-empty value="false" /> + <data-length-threshold value="100" /> + <popup-delay value="1000" /> + </text-editor-popup> + <values-actions-popup> + <show-popup-button value="true" /> + <element-count-threshold value="1000" /> + <data-length-threshold value="250" /> + </values-actions-popup> + <general> + <fetch-block-size value="100" /> + <fetch-timeout value="30" /> + <trim-whitespaces value="true" /> + <convert-empty-strings-to-null value="true" /> + <select-content-on-cell-edit value="true" /> + <large-value-preview-active value="true" /> + </general> + <filters> + <prompt-filter-dialog value="true" /> + <default-filter-type value="BASIC" /> + </filters> + <qualified-text-editor text-length-threshold="300"> + <content-types> + <content-type name="Text" enabled="true" /> + <content-type name="Properties" enabled="true" /> + <content-type name="XML" enabled="true" /> + <content-type name="DTD" enabled="true" /> + <content-type name="HTML" enabled="true" /> + <content-type name="XHTML" enabled="true" /> + <content-type name="CSS" enabled="true" /> + <content-type name="Java" enabled="true" /> + <content-type name="SQL" enabled="true" /> + <content-type name="PL/SQL" enabled="true" /> + <content-type name="JavaScript" enabled="true" /> + <content-type name="JSON" enabled="true" /> + <content-type name="JSON5" enabled="true" /> + <content-type name="PHP" enabled="true" /> + <content-type name="JSP" enabled="true" /> + <content-type name="JSPx" enabled="true" /> + <content-type name="FTL" enabled="true" /> + <content-type name="VTL" enabled="true" /> + <content-type name="YAML" enabled="true" /> + <content-type name="Manifest" enabled="true" /> + </content-types> + </qualified-text-editor> + <record-navigation> + <navigation-target value="VIEWER" /> + </record-navigation> + </dataset-editor-settings> + <code-editor-settings> + <general> + <show-object-navigation-gutter value="false" /> + <show-spec-declaration-navigation-gutter value="true" /> + <enable-spellchecking value="true" /> + <enable-reference-spellchecking value="false" /> + </general> + <confirmations> + <save-changes value="false" /> + <revert-changes value="true" /> + </confirmations> + </code-editor-settings> + <code-completion-settings> + <filters> + <basic-filter> + <filter-element type="RESERVED_WORD" id="keyword" selected="true" /> + <filter-element type="RESERVED_WORD" id="function" selected="true" /> + <filter-element type="RESERVED_WORD" id="parameter" selected="true" /> + <filter-element type="RESERVED_WORD" id="datatype" selected="true" /> + <filter-element type="RESERVED_WORD" id="exception" selected="true" /> + <filter-element type="OBJECT" id="schema" selected="true" /> + <filter-element type="OBJECT" id="role" selected="true" /> + <filter-element type="OBJECT" id="user" selected="true" /> + <filter-element type="OBJECT" id="privilege" selected="true" /> + <user-schema> + <filter-element type="OBJECT" id="table" selected="true" /> + <filter-element type="OBJECT" id="view" selected="true" /> + <filter-element type="OBJECT" id="materialized view" selected="true" /> + <filter-element type="OBJECT" id="index" selected="true" /> + <filter-element type="OBJECT" id="constraint" selected="true" /> + <filter-element type="OBJECT" id="trigger" selected="true" /> + <filter-element type="OBJECT" id="synonym" selected="false" /> + <filter-element type="OBJECT" id="sequence" selected="true" /> + <filter-element type="OBJECT" id="procedure" selected="true" /> + <filter-element type="OBJECT" id="function" selected="true" /> + <filter-element type="OBJECT" id="package" selected="true" /> + <filter-element type="OBJECT" id="type" selected="true" /> + <filter-element type="OBJECT" id="dimension" selected="true" /> + <filter-element type="OBJECT" id="cluster" selected="true" /> + <filter-element type="OBJECT" id="dblink" selected="true" /> + </user-schema> + <public-schema> + <filter-element type="OBJECT" id="table" selected="false" /> + <filter-element type="OBJECT" id="view" selected="false" /> + <filter-element type="OBJECT" id="materialized view" selected="false" /> + <filter-element type="OBJECT" id="index" selected="false" /> + <filter-element type="OBJECT" id="constraint" selected="false" /> + <filter-element type="OBJECT" id="trigger" selected="false" /> + <filter-element type="OBJECT" id="synonym" selected="false" /> + <filter-element type="OBJECT" id="sequence" selected="false" /> + <filter-element type="OBJECT" id="procedure" selected="false" /> + <filter-element type="OBJECT" id="function" selected="false" /> + <filter-element type="OBJECT" id="package" selected="false" /> + <filter-element type="OBJECT" id="type" selected="false" /> + <filter-element type="OBJECT" id="dimension" selected="false" /> + <filter-element type="OBJECT" id="cluster" selected="false" /> + <filter-element type="OBJECT" id="dblink" selected="false" /> + </public-schema> + <any-schema> + <filter-element type="OBJECT" id="table" selected="true" /> + <filter-element type="OBJECT" id="view" selected="true" /> + <filter-element type="OBJECT" id="materialized view" selected="true" /> + <filter-element type="OBJECT" id="index" selected="true" /> + <filter-element type="OBJECT" id="constraint" selected="true" /> + <filter-element type="OBJECT" id="trigger" selected="true" /> + <filter-element type="OBJECT" id="synonym" selected="true" /> + <filter-element type="OBJECT" id="sequence" selected="true" /> + <filter-element type="OBJECT" id="procedure" selected="true" /> + <filter-element type="OBJECT" id="function" selected="true" /> + <filter-element type="OBJECT" id="package" selected="true" /> + <filter-element type="OBJECT" id="type" selected="true" /> + <filter-element type="OBJECT" id="dimension" selected="true" /> + <filter-element type="OBJECT" id="cluster" selected="true" /> + <filter-element type="OBJECT" id="dblink" selected="true" /> + </any-schema> + </basic-filter> + <extended-filter> + <filter-element type="RESERVED_WORD" id="keyword" selected="true" /> + <filter-element type="RESERVED_WORD" id="function" selected="true" /> + <filter-element type="RESERVED_WORD" id="parameter" selected="true" /> + <filter-element type="RESERVED_WORD" id="datatype" selected="true" /> + <filter-element type="RESERVED_WORD" id="exception" selected="true" /> + <filter-element type="OBJECT" id="schema" selected="true" /> + <filter-element type="OBJECT" id="user" selected="true" /> + <filter-element type="OBJECT" id="role" selected="true" /> + <filter-element type="OBJECT" id="privilege" selected="true" /> + <user-schema> + <filter-element type="OBJECT" id="table" selected="true" /> + <filter-element type="OBJECT" id="view" selected="true" /> + <filter-element type="OBJECT" id="materialized view" selected="true" /> + <filter-element type="OBJECT" id="index" selected="true" /> + <filter-element type="OBJECT" id="constraint" selected="true" /> + <filter-element type="OBJECT" id="trigger" selected="true" /> + <filter-element type="OBJECT" id="synonym" selected="true" /> + <filter-element type="OBJECT" id="sequence" selected="true" /> + <filter-element type="OBJECT" id="procedure" selected="true" /> + <filter-element type="OBJECT" id="function" selected="true" /> + <filter-element type="OBJECT" id="package" selected="true" /> + <filter-element type="OBJECT" id="type" selected="true" /> + <filter-element type="OBJECT" id="dimension" selected="true" /> + <filter-element type="OBJECT" id="cluster" selected="true" /> + <filter-element type="OBJECT" id="dblink" selected="true" /> + </user-schema> + <public-schema> + <filter-element type="OBJECT" id="table" selected="true" /> + <filter-element type="OBJECT" id="view" selected="true" /> + <filter-element type="OBJECT" id="materialized view" selected="true" /> + <filter-element type="OBJECT" id="index" selected="true" /> + <filter-element type="OBJECT" id="constraint" selected="true" /> + <filter-element type="OBJECT" id="trigger" selected="true" /> + <filter-element type="OBJECT" id="synonym" selected="true" /> + <filter-element type="OBJECT" id="sequence" selected="true" /> + <filter-element type="OBJECT" id="procedure" selected="true" /> + <filter-element type="OBJECT" id="function" selected="true" /> + <filter-element type="OBJECT" id="package" selected="true" /> + <filter-element type="OBJECT" id="type" selected="true" /> + <filter-element type="OBJECT" id="dimension" selected="true" /> + <filter-element type="OBJECT" id="cluster" selected="true" /> + <filter-element type="OBJECT" id="dblink" selected="true" /> + </public-schema> + <any-schema> + <filter-element type="OBJECT" id="table" selected="true" /> + <filter-element type="OBJECT" id="view" selected="true" /> + <filter-element type="OBJECT" id="materialized view" selected="true" /> + <filter-element type="OBJECT" id="index" selected="true" /> + <filter-element type="OBJECT" id="constraint" selected="true" /> + <filter-element type="OBJECT" id="trigger" selected="true" /> + <filter-element type="OBJECT" id="synonym" selected="true" /> + <filter-element type="OBJECT" id="sequence" selected="true" /> + <filter-element type="OBJECT" id="procedure" selected="true" /> + <filter-element type="OBJECT" id="function" selected="true" /> + <filter-element type="OBJECT" id="package" selected="true" /> + <filter-element type="OBJECT" id="type" selected="true" /> + <filter-element type="OBJECT" id="dimension" selected="true" /> + <filter-element type="OBJECT" id="cluster" selected="true" /> + <filter-element type="OBJECT" id="dblink" selected="true" /> + </any-schema> + </extended-filter> + </filters> + <sorting enabled="true"> + <sorting-element type="RESERVED_WORD" id="keyword" /> + <sorting-element type="RESERVED_WORD" id="datatype" /> + <sorting-element type="OBJECT" id="column" /> + <sorting-element type="OBJECT" id="table" /> + <sorting-element type="OBJECT" id="view" /> + <sorting-element type="OBJECT" id="materialized view" /> + <sorting-element type="OBJECT" id="index" /> + <sorting-element type="OBJECT" id="constraint" /> + <sorting-element type="OBJECT" id="trigger" /> + <sorting-element type="OBJECT" id="synonym" /> + <sorting-element type="OBJECT" id="sequence" /> + <sorting-element type="OBJECT" id="procedure" /> + <sorting-element type="OBJECT" id="function" /> + <sorting-element type="OBJECT" id="package" /> + <sorting-element type="OBJECT" id="type" /> + <sorting-element type="OBJECT" id="dimension" /> + <sorting-element type="OBJECT" id="cluster" /> + <sorting-element type="OBJECT" id="dblink" /> + <sorting-element type="OBJECT" id="schema" /> + <sorting-element type="OBJECT" id="role" /> + <sorting-element type="OBJECT" id="user" /> + <sorting-element type="RESERVED_WORD" id="function" /> + <sorting-element type="RESERVED_WORD" id="parameter" /> + </sorting> + <format> + <enforce-code-style-case value="true" /> + </format> + </code-completion-settings> + <execution-engine-settings> + <statement-execution> + <fetch-block-size value="100" /> + <execution-timeout value="20" /> + <debug-execution-timeout value="600" /> + <focus-result value="false" /> + <prompt-execution value="false" /> + </statement-execution> + <script-execution> + <command-line-interfaces /> + <execution-timeout value="300" /> + </script-execution> + <method-execution> + <execution-timeout value="30" /> + <debug-execution-timeout value="600" /> + <parameter-history-size value="10" /> + </method-execution> + </execution-engine-settings> + <operation-settings> + <transactions> + <uncommitted-changes> + <on-project-close value="ASK" /> + <on-disconnect value="ASK" /> + <on-autocommit-toggle value="ASK" /> + </uncommitted-changes> + <multiple-uncommitted-changes> + <on-commit value="ASK" /> + <on-rollback value="ASK" /> + </multiple-uncommitted-changes> + </transactions> + <session-browser> + <disconnect-session value="ASK" /> + <kill-session value="ASK" /> + <reload-on-filter-change value="false" /> + </session-browser> + <compiler> + <compile-type value="KEEP" /> + <compile-dependencies value="ASK" /> + <always-show-controls value="false" /> + </compiler> + <debugger> + <debugger-type value="ASK" /> + <use-generic-runners value="true" /> + </debugger> + </operation-settings> + <ddl-file-settings> + <extensions> + <mapping file-type-id="VIEW" extensions="vw" /> + <mapping file-type-id="TRIGGER" extensions="trg" /> + <mapping file-type-id="PROCEDURE" extensions="prc" /> + <mapping file-type-id="FUNCTION" extensions="fnc" /> + <mapping file-type-id="PACKAGE" extensions="pkg" /> + <mapping file-type-id="PACKAGE_SPEC" extensions="pks" /> + <mapping file-type-id="PACKAGE_BODY" extensions="pkb" /> + <mapping file-type-id="TYPE" extensions="tpe" /> + <mapping file-type-id="TYPE_SPEC" extensions="tps" /> + <mapping file-type-id="TYPE_BODY" extensions="tpb" /> + </extensions> + <general> + <lookup-ddl-files value="true" /> + <create-ddl-files value="false" /> + <synchronize-ddl-files value="true" /> + <use-qualified-names value="false" /> + <make-scripts-rerunnable value="true" /> + </general> + </ddl-file-settings> + <general-settings> + <regional-settings> + <date-format value="MEDIUM" /> + <number-format value="UNGROUPED" /> + <locale value="SYSTEM_DEFAULT" /> + <use-custom-formats value="false" /> + </regional-settings> + <environment> + <environment-types> + <environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" /> + <environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" /> + <environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" /> + <environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" /> + </environment-types> + <visibility-settings> + <connection-tabs value="true" /> + <dialog-headers value="true" /> + <object-editor-tabs value="true" /> + <script-editor-tabs value="false" /> + <execution-result-tabs value="true" /> + </visibility-settings> + </environment> + </general-settings> + </component> + <component name="DBNavigator.Project.StatementExecutionManager"> + <execution-variables /> + </component> +</project> \ No newline at end of file diff --git a/.idea/markdown-navigator-enh.xml b/.idea/markdown-navigator-enh.xml new file mode 100644 index 0000000000000000000000000000000000000000..a8fcc84db3668cadd75348be61bda65a8fc5ea21 --- /dev/null +++ b/.idea/markdown-navigator-enh.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="MarkdownEnhProjectSettings"> + <AnnotatorSettings targetHasSpaces="true" linkCaseMismatch="true" wikiCaseMismatch="true" wikiLinkHasDashes="true" notUnderWikiHome="true" targetNotWikiPageExt="true" notUnderSourceWikiHome="true" targetNameHasAnchor="true" targetPathHasAnchor="true" wikiLinkHasSlash="true" wikiLinkHasSubdir="true" wikiLinkHasOnlyAnchor="true" linkTargetsWikiHasExt="true" linkTargetsWikiHasBadExt="true" notUnderSameRepo="true" targetNotUnderVcs="false" linkNeedsExt="true" linkHasBadExt="true" linkTargetNeedsExt="true" linkTargetHasBadExt="true" wikiLinkNotInWiki="true" imageTargetNotInRaw="true" repoRelativeAcrossVcsRoots="true" multipleWikiTargetsMatch="true" unresolvedLinkReference="true" linkIsIgnored="true" anchorIsIgnored="true" anchorIsUnresolved="true" anchorLineReferenceIsUnresolved="true" anchorLineReferenceFormat="true" anchorHasDuplicates="true" abbreviationDuplicates="true" abbreviationNotUsed="true" attributeIdDuplicateDefinition="true" attributeIdNotUsed="true" footnoteDuplicateDefinition="true" footnoteUnresolved="true" footnoteDuplicates="true" footnoteNotUsed="true" macroDuplicateDefinition="true" macroUnresolved="true" macroDuplicates="true" macroNotUsed="true" referenceDuplicateDefinition="true" referenceUnresolved="true" referenceDuplicates="true" referenceNotUsed="true" referenceUnresolvedNumericId="true" enumRefDuplicateDefinition="true" enumRefUnresolved="true" enumRefDuplicates="true" enumRefNotUsed="true" enumRefLinkUnresolved="true" enumRefLinkDuplicates="true" simTocUpdateNeeded="true" simTocTitleSpaceNeeded="true" /> + <HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="css" scriptDir="js" plainHtml="false" imageDir="" copyLinkedImages="false" imagePathType="0" targetPathType="2" targetExt="" useTargetExt="false" noCssNoScripts="false" useElementStyleAttribute="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" /> + <LinkMapSettings> + <textMaps /> + </LinkMapSettings> + </component> +</project> \ No newline at end of file diff --git a/.idea/markdown-navigator.xml b/.idea/markdown-navigator.xml new file mode 100644 index 0000000000000000000000000000000000000000..a2fc0864e7bc79d88eaf4d3f18785833dfe9d367 --- /dev/null +++ b/.idea/markdown-navigator.xml @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="MarkdownProjectSettings"> + <PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" synchronizePreviewPosition="true" highlightPreviewType="LINE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="true" showSelectionInPreview="true" lastLayoutSetsDefault="false"> + <PanelProvider> + <provider providerId="com.vladsch.md.nav.editor.swing.html.panel" providerName="Default - Swing" /> + </PanelProvider> + </PreviewSettings> + <ParserSettings gitHubSyntaxChange="false" correctedInvalidSettings="false" emojiShortcuts="1" emojiImages="0"> + <PegdownExtensions> + <option name="ATXHEADERSPACE" value="true" /> + <option name="FENCED_CODE_BLOCKS" value="true" /> + <option name="INTELLIJ_DUMMY_IDENTIFIER" value="true" /> + <option name="RELAXEDHRULES" value="true" /> + <option name="STRIKETHROUGH" value="true" /> + <option name="TABLES" value="true" /> + <option name="TASKLISTITEMS" value="true" /> + </PegdownExtensions> + <ParserOptions> + <option name="COMMONMARK_LISTS" value="true" /> + <option name="EMOJI_SHORTCUTS" value="true" /> + <option name="GFM_TABLE_RENDERING" value="true" /> + <option name="PRODUCTION_SPEC_PARSER" value="true" /> + <option name="SIM_TOC_BLANK_LINE_SPACER" value="true" /> + </ParserOptions> + </ParserSettings> + <HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" addPageHeader="false" addAnchorLinks="false" anchorLinksWrapText="false" imageUriSerials="false" addDocTypeHtml="true" noParaTags="false" defaultUrlTitle="false" migratedPlantUml="true" migratedAnchorLinks="true" plantUmlConversion="0"> + <GeneratorProvider> + <provider providerId="com.vladsch.md.nav.editor.text.html.generator" providerName="Unmodified HTML Generator" /> + </GeneratorProvider> + <headerTop /> + <headerBottom /> + <bodyTop /> + <bodyBottom /> + <fencedCodeConversions> + <option name="c4plantuml" value="NONE" /> + <option name="ditaa" value="NONE" /> + <option name="erd" value="NONE" /> + <option name="graphviz" value="NONE" /> + <option name="latex" value="KATEX" /> + <option name="math" value="KATEX" /> + <option name="mermaid" value="NONE" /> + <option name="nomnoml" value="NONE" /> + <option name="plantuml" value="NONE" /> + <option name="puml" value="NONE" /> + <option name="svgbob" value="NONE" /> + <option name="umlet" value="NONE" /> + <option name="vega" value="NONE" /> + <option name="vegalite" value="NONE" /> + <option name="wavedrom" value="NONE" /> + </fencedCodeConversions> + </HtmlSettings> + <CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="true" isCssTextEnabled="false" isDynamicPageWidth="true"> + <StylesheetProvider> + <provider providerId="com.vladsch.md.nav.editor.text.html.css" providerName="No Stylesheet" /> + </StylesheetProvider> + <ScriptProviders /> + <cssText /> + <cssUriHistory /> + </CssSettings> + </component> +</project> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..639900d13c6182e452e33a3bd638e70a0146c785 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager"> + <output url="file://$PROJECT_DIR$/out" /> + </component> +</project> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..125cecf7c178caac7bccbe1874f03f00eb438e52 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/connection-checker.iml" filepath="$PROJECT_DIR$/connection-checker.iml" /> + <module fileurl="file://$PROJECT_DIR$/gateway/gateway.iml" filepath="$PROJECT_DIR$/gateway/gateway.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/.idea/runConfigurations/go_build_connection_checker.xml b/.idea/runConfigurations/go_build_connection_checker.xml new file mode 100644 index 0000000000000000000000000000000000000000..1dddf38793bc20a64332a7b2baf72a257ce8220b --- /dev/null +++ b/.idea/runConfigurations/go_build_connection_checker.xml @@ -0,0 +1,21 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="go build connection-checker" type="GoApplicationRunConfiguration" factoryName="Go Application"> + <module name="connection-checker" /> + <working_directory value="$PROJECT_DIR$" /> + <sudo value="true" /> + <EXTENSION ID="net.ashald.envfile"> + <option name="IS_ENABLED" value="false" /> + <option name="IS_SUBST" value="false" /> + <option name="IS_PATH_MACRO_SUPPORTED" value="false" /> + <option name="IS_IGNORE_MISSING_FILES" value="false" /> + <option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" /> + <ENTRIES> + <ENTRY IS_ENABLED="true" PARSER="runconfig" /> + </ENTRIES> + </EXTENSION> + <kind value="DIRECTORY" /> + <directory value="$PROJECT_DIR$" /> + <filePath value="$PROJECT_DIR$" /> + <method v="2" /> + </configuration> +</component> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..35eb1ddfbbc029bcab630581847471d7f238ec53 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="" vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3120e2de0feff1f74f5314d121ea79d2118e3600 --- /dev/null +++ b/Makefile @@ -0,0 +1,47 @@ +PROJECT_NAME := "connection-checker" +PKG := "gitlab.schukai.com/oss/utilities/network/connection-checker" +PKG_LIST := $(shell go list ${PKG}/... ) +GO_FILES := $(shell find . -name '*.go') + +GOCMD=go +GOBUILD=$(GOCMD) build +GOCLEAN=$(GOCMD) clean +GOTEST=$(GOCMD) test +GOVET=$(GOCMD) vet +GOGET=$(GOCMD) get +GOFMT=$(GOCMD) fmt +GODOC=$(GOCMD) fmt +GOLINT=golint + +default: help + +help: ## show this help + @echo 'usage: make [target] ...' + @echo '' + @echo 'targets:' + @egrep '^(.+)\:\ .*##\ (.+)' ${MAKEFILE_LIST} | sed 's/:.*##/#/' | column -t -c 2 -s '#' + +clean: ## go clean + $(GOCLEAN) + +clean-all: ## remove all generated artifacts and clean all build artifacts + $(GOCLEAN) -i ./... + +lint: ## run go lint on the source files + $(GOLINT) -set_exit_status . + +doc: ## generate godocs and start a local documentation webserver on port 8085 + godoc -http=:8085 -index + +fmt: ## format the go source files + $(GOFMT) . + +all: ## clean, format and build + make clean-all + make fmt + make build + +build: + mkdir -p bin + $(GOCMD) build -o bin/nck + sudo setcap cap_net_raw+ep bin/nck diff --git a/README.md b/README.md index 84103fcdd3febb61cae7b656d7f9fedde899b9d0..971e33f66c67eecac648d2dc7c0fa89d192b8d6c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,48 @@ -# connection checker +# Connection Checker Nck -the connection checker tests the internet connection and displays the status on the console \ No newline at end of file +This utility `nck` works similiar to traceroute and +allows to record a traceroute. + +## Requirements + +To execute the traceroute, a privileged port must be opened. this +requires special permissions. + +A prerequisite for reading incoming traffic is being able to either to +be root or set the executable capability `CAP_NET_RAW`. + +Reminder: You can set the `CAP_NET_RAW` capability on an executable like +this: `sudo setcap cap_net_raw+ep bin/nck` + +the connection checker tests the internet connection and displays the status on the console + +## Build + +Make build uses sudo to set the authorization for the program (see +Requirements). + +``` +make build +``` + + +## Run + +```bash +Usage: + nck is the way to measure the path to a host. + +With this command the path from the localhost to the +target computer can be recorded and the duration of the +packet runtimes can be measured. Depending on the IP +of the destination, either a V4 or V6 measurement is performed. + +Application Options: + -r, --realtime show the steps in real time + -f, --format=[table] output format, is not valid for real time mode. (default: table) + -h, --hops= maximal hops. + -m, --threshold= from the threshold value in milliseconds the value is marked in red (default: 20) + +Help Options: + -h, --help Show this help message +``` diff --git a/connection-checker.iml b/connection-checker.iml new file mode 100644 index 0000000000000000000000000000000000000000..49df094a939bad91c791b0986d7e479bcc496640 --- /dev/null +++ b/connection-checker.iml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="WEB_MODULE" version="4"> + <component name="Go" enabled="true" /> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$" /> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> +</module> \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..c4886ea5c1b8eedbdca4ecd29759e38870529232 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module gitlab.schukai.com/oss/utilities/network/connection-checker + +go 1.16 + +require ( + github.com/fatih/color v1.11.0 + github.com/jessevdk/go-flags v1.5.0 + github.com/mattn/go-runewidth v0.0.12 // indirect + github.com/olekukonko/tablewriter v0.0.5 + github.com/rivo/uniseg v0.2.0 // indirect + gitlab.schukai.com/oss/libraries/go/network/traceroute v1.0.0 + golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..6246ee80a7cbe899ed906eb621f48523d3ea21bf --- /dev/null +++ b/go.sum @@ -0,0 +1,41 @@ +github.com/creasty/defaults v1.5.1 h1:j8WexcS3d/t4ZmllX4GEkl4wIB/trOr035ajcLHCISM= +github.com/creasty/defaults v1.5.1/go.mod h1:FPZ+Y0WNrbqOVw+c6av63eyHUAl6pMHZwqLPvXUZGfY= +github.com/fatih/color v1.11.0 h1:l4iX0RqNnx/pU7rY2DB/I+znuYY0K3x6Ywac6EIr0PA= +github.com/fatih/color v1.11.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/jackpal/gateway v1.0.7 h1:7tIFeCGmpyrMx9qvT0EgYUi7cxVW48a0mMvnIL17bPM= +github.com/jackpal/gateway v1.0.7/go.mod h1:aRcO0UFKt+MgIZmRmvOmnejdDT4Y1DNiNOsSd1AcIbA= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +gitlab.schukai.com/oss/libraries/go/network/traceroute v0.0.0-20210515170318-b9fafad6e994 h1:On/ql5GyUkvKGyhHU9dmEek6L+qhcoHdh0uE1SIn0lA= +gitlab.schukai.com/oss/libraries/go/network/traceroute v0.0.0-20210515170318-b9fafad6e994/go.mod h1:i8zDawbOZ1d6p7iIN/md3yMNreZ5gGuLlQtSRGo17VY= +gitlab.schukai.com/oss/libraries/go/network/traceroute v0.0.0-20210516184908-c276f482ab77 h1:Sfgyw8eg8uDA28TUl/HF6ktSucGYPmLemnQgVVJzcZ8= +gitlab.schukai.com/oss/libraries/go/network/traceroute v0.0.0-20210516184908-c276f482ab77/go.mod h1:i8zDawbOZ1d6p7iIN/md3yMNreZ5gGuLlQtSRGo17VY= +gitlab.schukai.com/oss/libraries/go/network/traceroute v1.0.0 h1:abu2nCfgmn3RjkWS+IinUtHo/1RQ2yebJ5ZeVuykRpQ= +gitlab.schukai.com/oss/libraries/go/network/traceroute v1.0.0/go.mod h1:i8zDawbOZ1d6p7iIN/md3yMNreZ5gGuLlQtSRGo17VY= +golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000000000000000000000000000000000000..009c0460847f17346a1927ca0913cb1a6ff52877 --- /dev/null +++ b/main.go @@ -0,0 +1,150 @@ +package main + +import ( + "errors" + "fmt" + "github.com/fatih/color" + "github.com/jessevdk/go-flags" + "github.com/olekukonko/tablewriter" + "gitlab.schukai.com/oss/libraries/go/network/traceroute" + "os" + "strconv" + "time" +) + +const ( + exitOK = 0 /* successful termination */ + exitUsage = 64 /* command line usage error */ + exitIOErr = 74 /* input/output error */ +) + +var opts struct { + Realtime bool `long:"realtime" short:"r" description:"show the steps in real time"` + Format string `long:"format" short:"f" description:"output format, is not valid for real time mode." choice:"table" default:"table"` + Hops int `long:"hops" short:"h" description:"maximal hops."` + Threshold int `long:"threshold" short:"m" description:"from the threshold value in milliseconds the value is marked in red" default:"20"` +} + +var parser *flags.Parser + +func round(d time.Duration, digits int) time.Duration { + + var divs = []time.Duration{ + time.Duration(1), time.Duration(10), time.Duration(100), time.Duration(1000)} + + switch { + case d > time.Second: + d = d.Round(time.Second / divs[digits]) + case d > time.Millisecond: + d = d.Round(time.Millisecond / divs[digits]) + case d > time.Microsecond: + d = d.Round(time.Microsecond / divs[digits]) + } + return d +} + +func printAsTable(result traceroute.Results) { + + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"#", "host", "time"}) + table.SetColumnAlignment([]int{tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_RIGHT}) + + table.NumLines() + table.SetBorders(tablewriter.Border{ + Left: false, + Right: false, + Top: false, + Bottom: false, + }) + + d := time.Duration(opts.Threshold) + marker := d * time.Millisecond + + for _, i := range result.Hops { + + r := []string{ + strconv.FormatInt(int64(i.Hop), 10), + i.Station, + fmt.Sprintf("%s", round(i.Latency, 3))} + + if i.Latency > marker { + table.Rich(r, []tablewriter.Colors{tablewriter.Colors{}, tablewriter.Colors{}, tablewriter.Colors{tablewriter.Bold, tablewriter.FgRedColor}}) + } else { + table.Append(r) + } + + } + + table.Render() // Send output + +} + +func printErrorAndExit(err error, exitcode int) { + + out := color.New(color.FgRed).Add(color.Underline) + + fmt.Println() + out.Println(err.Error()) + + fmt.Println() + parser.WriteHelp(os.Stdout) + fmt.Println() + os.Exit(exitcode) +} + +func main() { + + parser = flags.NewParser(&opts, flags.HelpFlag|flags.PrintErrors) + parser.Usage = "is the way to measure the path to a host." + parser.ShortDescription = "Traceroute to host." + parser.LongDescription = "With this command the path from the localhost to the\n" + + "target computer can be recorded and the duration of the\n" + + "packet runtimes can be measured. Depending on the IP\n" + + "of the destination, either a V4 or V6 measurement is performed." + + args, err := parser.Parse() + + if len(args) != 1 || args[0] == "" { + printErrorAndExit(errors.New("the required `host' was not specified"), exitUsage) + } + + session, err := traceroute.NewSession(args[0]) + if err != nil { + printErrorAndExit(err, exitIOErr) + return + } + + if opts.Hops > 0 { + session.MaxHops = opts.Hops + } + + if opts.Realtime { + session.CallBack = func(result traceroute.Result) { + if result.Err != nil { + fmt.Printf("%v\t%s\t\t\t\t%v\t\t(%s)\n", result.Hop, result.Station, result.Latency, result.Err.Error()) + return + } + + fmt.Printf("%v\t%s\t\t\t%v\n", result.Hop, result.Station, result.Latency) + } + } + + results, err := session.TraceRoute() + + if err != nil { + printErrorAndExit(err, exitIOErr) + } + + if opts.Realtime { + os.Exit(exitOK) + } + + switch opts.Format { + case "table": + printAsTable(*results) + default: + printErrorAndExit(errors.New("unsupported format"), exitUsage) + } + + os.Exit(exitOK) +}