{"id":17180755,"url":"https://github.com/dhowden/mindmeld","last_synced_at":"2025-10-25T01:04:41.858Z","repository":{"id":47268094,"uuid":"367782067","full_name":"dhowden/mindmeld","owner":"dhowden","description":null,"archived":false,"fork":false,"pushed_at":"2021-09-10T11:37:10.000Z","size":35,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-30T03:15:14.011Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dhowden.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}},"created_at":"2021-05-16T04:10:23.000Z","updated_at":"2021-09-15T05:29:07.000Z","dependencies_parsed_at":"2022-09-26T20:30:54.996Z","dependency_job_id":null,"html_url":"https://github.com/dhowden/mindmeld","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dhowden%2Fmindmeld","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dhowden%2Fmindmeld/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dhowden%2Fmindmeld/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dhowden%2Fmindmeld/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dhowden","download_url":"https://codeload.github.com/dhowden/mindmeld/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245377958,"owners_count":20605374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-10-15T00:31:27.737Z","updated_at":"2025-10-25T01:04:41.775Z","avatar_url":"https://github.com/dhowden.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mindmeld\n\n...is a toy project for port-forwarding between machines on the internet.  It works by passing traffic through an intermediary server which is reachable by all parties.\n\nIt uses gRPC streaming to pass control messages and proxy traffic, which means that the intermediary server can run in [Cloud Run](https://cloud.google.com/run).\n\n## Motivation\n\nIn pre-COVID times we would often port-forward between machines  to quickly test new servers as they were being developed.  When everyone was in the same room this was easy!  Working remotely has made this a lot more complex...\n\nAlthough there are a lot of existing solutions out there for this, seemed like an interesting problem to tackle - especially from the point of view of trying to make it as simple as possible, and practical to run (i.e. not too expensive).\n\n## Design\n\nThere are two main pieces which make the system work:\n* `router`: the intermediary process (see `cmd/crrouter`, named as it is the Cloud Run variant of the original `mmrouter`).\n* `client` the CLI tool run by users to create/use forwards (see `cmd/mmclient`).\n\n### Creating a service\n\nUsers share a local forward on their machine by registering a `service`.\n\n1. Client process calls `CreateService` which creates the service in `router`, and waits for forward requests to come through.\n1. When a forward request arrives on the `router` it responds to the `client` via the response stream waiting on the `CreateService` request, signalling it to create a new proxying connection to handle the traffic for the new forward.  The connection is given a `token` which identifies it when it is received by the `router`.\n1. When the proxying request arrives at the `router`, it matches it to the forward (using the `token`) and bridges the two connections.\n\nUsers access a `service` by:\n\n1. Client exposes a local port, which has a TCP listener.  Connections made to this listener will be forwarded to the service.\n1. For each new connection, the client process calls `ForwardToService` which checks the service still exists, and returns a `token` to identify the proxying connection.\n2. Client creates a proxying connection, using the provided `token`, and begins to copy data between the local connection and the proxying connection.\n\n## Emulating net.Conn with gRPC\n\nThe code was initially designed so that a separate TCP server would run on the router and host the proxy connections. Though easier to debug, this meant it couldn't be used in Cloud Run.\n\nSince Cloud Run was [updated](https://cloud.google.com/blog/products/serverless/cloud-run-gets-websockets-http-2-and-grpc-bidirectional-streams) to support gRPC bi-directional streaming, it was suddenly a possibility!\n\nThe proxying connections are now handled via `internal/protoproxy` which creates implementations of `net.Conn` and `net.Listener` to translate calls to `Write` into stream sends, calls to `Read` into stream receives, and `Accept` into new connections.\n\nThe tricky bit is correctly handling when a connection closes, and so there are likely some lingering bugs here.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdhowden%2Fmindmeld","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdhowden%2Fmindmeld","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdhowden%2Fmindmeld/lists"}