{"id":42745179,"url":"https://github.com/schwarzlichtbezirk/pds","last_synced_at":"2026-01-29T19:12:16.024Z","repository":{"id":57566123,"uuid":"339070240","full_name":"schwarzlichtbezirk/pds","owner":"schwarzlichtbezirk","description":"Client and server test sample with gRPC streaming and REST functionality.","archived":false,"fork":false,"pushed_at":"2024-10-29T11:59:51.000Z","size":355,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-14T17:43:08.962Z","etag":null,"topics":["golang","grpc","grpc-go","rest-api"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/schwarzlichtbezirk.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-02-15T12:27:03.000Z","updated_at":"2024-10-29T11:59:55.000Z","dependencies_parsed_at":"2022-08-27T19:01:21.601Z","dependency_job_id":null,"html_url":"https://github.com/schwarzlichtbezirk/pds","commit_stats":null,"previous_names":["schwarzlichtbezirk/pds-grpc"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/schwarzlichtbezirk/pds","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schwarzlichtbezirk%2Fpds","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schwarzlichtbezirk%2Fpds/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schwarzlichtbezirk%2Fpds/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schwarzlichtbezirk%2Fpds/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schwarzlichtbezirk","download_url":"https://codeload.github.com/schwarzlichtbezirk/pds/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schwarzlichtbezirk%2Fpds/sbom","scorecard":{"id":804519,"data":{"date":"2025-08-11","repo":{"name":"github.com/schwarzlichtbezirk/pds","commit":"37cca8f9bedfb1509954241011c801e56978be62"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.4,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/25 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: client.dockerfile:6","Warn: containerImage not pinned by hash: client.dockerfile:35: pin your Docker image by updating gcr.io/distroless/base-debian11 to gcr.io/distroless/base-debian11@sha256:ac69aa622ea5dcbca0803ca877d47d069f51bd4282d5c96977e0390d7d256455","Warn: containerImage not pinned by hash: server.dockerfile:6","Warn: containerImage not pinned by hash: server.dockerfile:35: pin your Docker image by updating gcr.io/distroless/base-debian11 to gcr.io/distroless/base-debian11@sha256:ac69aa622ea5dcbca0803ca877d47d069f51bd4282d5c96977e0390d7d256455","Info:   0 out of   4 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":7,"reason":"3 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T11:24:55.567Z","repository_id":57566123,"created_at":"2025-08-23T11:24:55.567Z","updated_at":"2025-08-23T11:24:55.567Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28882824,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-29T16:41:59.663Z","status":"ssl_error","status_checked_at":"2026-01-29T16:39:39.641Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","grpc","grpc-go","rest-api"],"created_at":"2026-01-29T19:12:15.286Z","updated_at":"2026-01-29T19:12:16.020Z","avatar_url":"https://github.com/schwarzlichtbezirk.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Port Domain Servece\n\nClient and server test sample with gRPC streaming and REST functionality. Sample features:\n\n- REST service.\n- gRPC service.\n- load balancing for gRPC backend.\n- uniform code style with documentation.\n- errors checking at all source code points.\n- domain driven design.\n- single application configuration.\n- safely servers start and graceful shutdown.\n- runnable at pure host, at standalone containers, at composite bundle.\n\n## Source code structure\n\n### client\n\n- `main.go` is file with main function only, contains workflow functions calls.\n- `workflow.go` contains functions for initialization, starts of services, wait for break, and finalization function with graceful shutdown of services.\n- `config.go`, all settings of application are collected into single structure with single initialization. This singleton can be streamed into JSON or YAML file.\n- `router.go` have a routing for HTTP-server, and some auxiliary functions for HTTP handlers.\n- `handlers.go` contains the list of HTTP handlers and error codes for them.\n- `io.go` reads settings from configuration file. Reads `port.json` file with predefined data format, and sends items step-by-step to gRPC server. File does not limited by size.\n- `auxiliary.go` have helper function to expand environment variables in the file path.\n\n### server\n\n- `main.go` is file with main function only, contains workflow functions calls.\n- `workflow.go` contains functions for initialization, starts of services, wait for break, and finalization function with graceful shutdown of services.\n- `config.go`, all settings of application are collected into single structure with single initialization. This singleton can be streamed into JSON or YAML file.\n- `grpcserv.go` have gRPC interface implementation for server.\n- `io.go` reads settings from configuration file.\n- `auxiliary.go` have helper function to expand environment variables in the file path.\n\n### pb\n\nHere is `pds.proto` with gRPC interface declaration, and files produced by protobuf compiler.\n\n## How to install\n\n1. First of all install [Golang](https://go.dev/dl/) of last version. Requires that [GOPATH is set](https://golang.org/doc/code.html#GOPATH). Be sure that `PATH` environment variable contains `%GOPATH%/bin` chunk. It's needed to run plugins for `protoc` compiler.\n\n2. Install [protocol buffer compiler](https://github.com/protocolbuffers/protobuf/blob/master/README.md#protocol-compiler-installation).\n\n3. Clone this git repo and run `task/gitdeploy.cmd` batch-file placed in project to deploy all dependencies.\n\n```batch\ngit clone github.com/schwarzlichtbezirk/pds\ncd pds\ncall task/gitdeploy.cmd\n```\n\n## How to run on localhost\n\nFolder `github.com/schwarzlichtbezirk/pds/task` contains batch helpers to compile services for Windows for x86 and amd64 platforms. Also it has shell-scripts to compile for Linux amd64 platforms. So, compile application by `task/build.win.x64.cmd` (or batch for x86), and run `task/start.x64.cmd` batch-file to start composition of client and server.\n\n## Connections\n\nPorts thats used at network are defined in configuration of server and client (see files `config.go`).\n\nServer listen on `50051` and `50052` ports by default, and it can be a list for load balancing.\n\nClient creates connection to gRPC server on the same ports. There is used `round_robin` load balancer policy. Hosts can be defined by environment variable `ADDRGRPC` with the list of values `addr:port` devided by semicolons, and if it not defined or empty, `localhost:50051;localhost:50052` is used. Also client opens `8008` port by default to listen for incoming connections to serve REST API, and it can be a list for load balancing.\n\nOn localhost server and client can be run as is without any modifications in configuration.\n\n## How to run in docker\n\n1. Change current directory to project root.\n\n```batch\ncd /d %GOPATH%/src/github.com/schwarzlichtbezirk/pds\n```\n\n2. Build docker images for `server` and for `client` services.\n\n```batch\ndocker build --pull --rm -f \"server.dockerfile\" -t pds-server:latest \".\"\ndocker build --pull --rm -f \"client.dockerfile\" -t pds-client:latest \".\"\n```\n\n3. Then run docker compose file.\n\n```batch\ndocker-compose -f \"docker-compose.yaml\" up -d --build\n```\n\n### Run standalone containers\n\nCreate a network, its created only once.\n\n```batch\ndocker network create -d bridge --subnet 172.20.0.0/16 pds-net\n```\n\nThen it should be run containers on `pds-net` network.\n\n```batch\ndocker run --rm -d -p 50051:50051 -p 50052:50052 --network=pds-net --ip=172.20.1.7 --name server pds-server\ndocker run --rm -d -p 8008:8008 --network=pds-net --ip=172.20.1.8 -e ADDRGRPC=\"172.20.1.7:50051;172.20.1.7:50052\" --name client pds-client\n```\n\n### Run by docker compose file\n\nDocker compose file uses already builded images and creates internal network for containers.\n\n## REST API\n\nArguments of all API calls placed as JSON-objects at request body. Replies comes also only as JSON-objects in all cases.\n\nErrors come on replies with status \u003e= 300 as objects like `{\"what\":\"some error message\",\"when\":1613251727492,\"code\":3}` where `when` is Unix time in milliseconds of error occurrence, `code` is unique error source point code.\n\n### Store port object `/api/port/set`\n\nStore port object to database, or replace with existing key (that placed in `unlocs` field of object).\n\n```batch\ncurl -d \"{\\\"name\\\":\\\"Dubai\\\",\\\"city\\\":\\\"Dubai\\\",\\\"country\\\":\\\"United Arab Emirates\\\",\\\"coordinates\\\":[55.27,25.25],\\\"province\\\":\\\"Dubayy [Dubai]\\\",\\\"timezone\\\":\\\"Asia/Dubai\\\",\\\"unlocs\\\":[\\\"AEDXB\\\"],\\\"code\\\":\\\"52005\\\"}\" -X POST localhost:8008/api/port/set\n\n{\"value\":\"AEDXB\"}\n```\n\n### Get port object by key `/api/port/get`\n\nReturns port object with given associated key.\n\n```batch\ncurl -d \"{\\\"value\\\":\\\"AEDXB\\\"}\" -X POST localhost:8008/api/port/get\n\n{\"name\":\"Dubai\",\"city\":\"Dubai\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.27,25.25],\"province\":\"Dubayy [Dubai]\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AEDXB\"],\"code\":\"52005\"}\n```\n\n### Get port object by name `/api/port/name`\n\nReturns port object with given name. It's looking for port with strict name match.\n\n```batch\ncurl -d \"{\\\"value\\\":\\\"Dubai\\\"}\" -X POST localhost:8008/api/port/name\n\n{\"name\":\"Dubai\",\"city\":\"Dubai\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.27,25.25],\"province\":\"Dubayy [Dubai]\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AEDXB\"],\"code\":\"52005\"}\n```\n\n### Find nearest port `/api/port/near`\n\nFinds nearest Port to given coordinates. Recieves `Point` with searching latitude and longitude and returns port with nearest coodinates to given point. Be considered that at port coordinates first value is longitude, second value is latitude.\n\n```batch\ncurl -d \"{\\\"latitude\\\":25.873280,\\\"longitude\\\":55.011377}\" -X POST localhost:8008/api/port/near\n\n{\"name\":\"Umm al Qaiwain\",\"city\":\"Umm al Qaiwain\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.55,25.57],\"province\":\"Umm Al Quwain\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AEQIW\"]}\n```\n\n### Find ports in circle `/api/port/circle`\n\nFinds all ports in given circle. Circle determined by latitude/longitude point of center, and radius in meters.\n\n```batch\ncurl -d \"{\\\"center\\\":{\\\"latitude\\\":25.458155,\\\"longitude\\\":55.148621},\\\"radius\\\":40000}\" -X POST localhost:8008/api/port/circle\n\n{\"list\":[{\"name\":\"Sharjah\",\"city\":\"Sharjah\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.38,25.35],\"province\":\"Ash Shariqah [Sharjah]\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AESHJ\"],\"code\":\"52070\"},{\"name\":\"Dubai\",\"city\":\"Dubai\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.27,25.25],\"province\":\"Dubayy [Dubai]\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AEDXB\"],\"code\":\"52005\"},{\"name\":\"Ajman\",\"city\":\"Ajman\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.513645,25.405216],\"province\":\"Ajman\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AEAJM\"],\"code\":\"52000\"},{\"name\":\"Port Rashid\",\"city\":\"Port Rashid\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.27565,25.284756],\"province\":\"Dubai\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AEPRA\"],\"code\":\"52005\"}]}\n```\n\n### Find ports with text `/api/port/text`\n\nFinds all ports each of which contains given text in one of the fields: name, city, province, country. Field `sensitive` of argument makes search case sensitive; `whole` matches entire string. Returns list of founded ports if it has.\n\n```batch\ncurl -d \"{\\\"value\\\":\\\"dubai\\\",\\\"whole\\\":true}\" -X POST localhost:8008/api/port/text\n\n{\"list\":[{\"name\":\"Dubai\",\"city\":\"Dubai\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.27,25.25],\"province\":\"Dubayy [Dubai]\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AEDXB\"],\"code\":\"52005\"},{\"name\":\"Port Rashid\",\"city\":\"Port Rashid\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.27565,25.284756],\"province\":\"Dubai\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AEPRA\"],\"code\":\"52005\"},{\"name\":\"Jebel Ali\",\"city\":\"Jebel Ali\",\"country\":\"United Arab Emirates\",\"coordinates\":[55.02729,24.985714],\"province\":\"Dubai\",\"timezone\":\"Asia/Dubai\",\"unlocs\":[\"AEJEA\"],\"code\":\"52051\"}]}\n```\n\n```batch\ncurl -d \"{\\\"value\\\":\\\"miam\\\",\\\"whole\\\":false}\" -X POST localhost:8008/api/port/text\n\n{\"list\":[{\"name\":\"Miami\",\"city\":\"Miami\",\"country\":\"United States\",\"coordinates\":[-80.19179,25.76168],\"province\":\"Florida\",\"timezone\":\"America/New_York\",\"unlocs\":[\"USMIA\"],\"code\":\"5201\"}]}\n```\n\n---\n(c) schwarzlichtbezirk, 2021.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschwarzlichtbezirk%2Fpds","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fschwarzlichtbezirk%2Fpds","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschwarzlichtbezirk%2Fpds/lists"}