Integrating Clash in Go

Integrating Clash in Go explains configuration ownership, lifecycle control and runtime state handling for application integrations.

Overview

Integrating Clash in a Go program means controlling or embedding Clash behavior from application code. The important part is to keep configuration, lifecycle and runtime state explicit.

Integration model

A Go application can start a core, load configuration, watch profile changes, query runtime state or interact with the external controller API.

Engineering notes

  • Validate profiles before loading them.
  • Keep logs accessible for user support.
  • Handle shutdown so ports and TUN devices are released cleanly.
  • Avoid hiding subscription URLs in crash reports or debug output.

Support Checks

Most integration bugs are lifecycle issues: ports not released, stale profiles, missing permissions, or controller calls made before the core is ready.

Reference examples

These examples mirror the corresponding Chinese documentation page so the English page carries the same configuration material.

package main

import (
	"context"
	"fmt"
	"io"
	"net"

	"github.com/Dreamacro/clash/adapter/outbound"
	"github.com/Dreamacro/clash/constant"
	"github.com/Dreamacro/clash/listener/socks"
)

func main() {
	in := make(chan constant.ConnContext, 100)
	defer close(in)

	l, err := socks.New("127.0.0.1:10000", in)
	if err != nil {
		panic(err)
	}
	defer l.Close()

	println("listen at:", l.Address())

	direct := outbound.NewDirect()

	for c := range in {
		conn := c
		metadata := conn.Metadata()
		# reference note
		go func () {
			remote, err := direct.DialContext(context.Background(), metadata)
			if err != nil {
				# reference note
				return
			}
			relay(remote, conn.Conn())
		}()
	}
}

func relay(l, r net.Conn) {
	go io.Copy(l, r)
	io.Copy(r, l)
}