<commit_before>package main

import (
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"strings"
	"time"
)

type StoppableListener struct {
	*net.UnixListener
	done chan error
}

func (s *StoppableListener) Accept() (net.Conn, error) {
	for {
		s.SetDeadline(time.Now().Add(time.Second))

		select {
		case <-s.done:
			return nil, fmt.Errorf("Xhyve exited, stopping proxy")
		default:
		}

		newConn, err := s.UnixListener.Accept()
		if err != nil {
			netErr, ok := err.(net.Error)
			if ok && netErr.Timeout() && netErr.Temporary() {
				continue
			}
		}

		return newConn, err
	}
}

func (s *StoppableListener) Close() error {
	close(s.done)
	DetachDisk()
	return nil
}

func Proxy(ip string, done chan error) error {
	_, err := os.Stat("/var/run/docker.sock")
	if err == nil {
		err = os.Remove("/var/run/docker.sock")
		if err != nil {
			return err
		}
	}

	addr, err := net.ResolveUnixAddr("unix", "/var/run/docker.sock")
	if err != nil {
		return err
	}

	rawListener, err := net.ListenUnix("unix", addr)
	if err != nil {
		return err
	}

	listener := &StoppableListener{UnixListener: rawListener, done: done}

	err = os.Chmod("/var/run/docker.sock", 0777)
	if err != nil {
		return err
	}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		r.URL.Scheme = "http"
		r.URL.Host = ip + ":2375"

		upgrade := false
		if strings.HasSuffix(r.URL.Path, "/attach") {
			upgrade = true
		} else if len(r.Header["Upgrade"]) > 0 {
			upgrade_header := strings.ToLower(r.Header["Upgrade"][0])
			upgrade = upgrade_header == "tcp" || upgrade_header == "websocket"
		}

		if upgrade {
			hj, ok := w.(http.Hijacker)
			if !ok {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			conn, _, err := hj.Hijack()
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			defer conn.Close()

			backend, err := net.Dial("tcp", ip+":2375")
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			defer backend.Close()

			err = r.Write(backend)
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			finished := make(chan bool, 1)
			go func() {
				io.Copy(backend, conn)
			}()

			go func() {
				io.Copy(conn, backend)
				finished <- true
			}()

			<-finished
		} else {
			resp, err := http.DefaultTransport.RoundTrip(r)
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			defer resp.Body.Close()<commit_msg>finish proxy refactor, closes #122<commit_after>package main

import (
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"strings"
	"time"
)

type StoppableListener struct {
	*net.UnixListener
	done chan error
}

func (s *StoppableListener) Accept() (net.Conn, error) {
	for {
		s.SetDeadline(time.Now().Add(time.Second))

		select {
		case <-s.done:
			return nil, fmt.Errorf("Xhyve exited, stopping proxy")
		default:
		}

		newConn, err := s.UnixListener.Accept()
		if err != nil {
			netErr, ok := err.(net.Error)
			if ok && netErr.Timeout() && netErr.Temporary() {
				continue
			}
		}

		return newConn, err
	}
}

func (s *StoppableListener) Close() error {
	close(s.done)
	return nil
}

func Proxy(ip string, done chan error) error {
	_, err := os.Stat("/var/run/docker.sock")
	if err == nil {
		err = os.Remove("/var/run/docker.sock")
		if err != nil {
			return err
		}
	}

	addr, err := net.ResolveUnixAddr("unix", "/var/run/docker.sock")
	if err != nil {
		return err
	}

	rawListener, err := net.ListenUnix("unix", addr)
	if err != nil {
		return err
	}

	listener := &StoppableListener{UnixListener: rawListener, done: done}

	err = os.Chmod("/var/run/docker.sock", 0777)
	if err != nil {
		return err
	}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		r.URL.Scheme = "http"
		r.URL.Host = ip + ":2375"

		upgrade := false
		if strings.HasSuffix(r.URL.Path, "/attach") {
			upgrade = true
		} else if len(r.Header["Upgrade"]) > 0 {
			upgrade_header := strings.ToLower(r.Header["Upgrade"][0])
			upgrade = upgrade_header == "tcp" || upgrade_header == "websocket"
		}

		if upgrade {
			hj, ok := w.(http.Hijacker)
			if !ok {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			conn, _, err := hj.Hijack()
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			addr, err := net.ResolveTCPAddr("tcp", ip+":2375")
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			backend, err := net.DialTCP("tcp", nil, addr)
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			finished := make(chan error, 1)

			go func() {
				_, err := io.Copy(conn, backend)
				conn.Close()
				finished <- err
			}()

			go func() {
				_, err := io.Copy(backend, conn)
				backend.CloseWrite()
				finished <- err
			}()

			r.Write(backend)
			defer r.Body.Close()
			defer backend.Close()

			<-finished
			<-finished
		} else {
			resp, err := http.DefaultTransport.RoundTrip(r)
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			defer resp.Body.Close()
{'fraction_non_alphanumeric': 0.155053974484789, 'fraction_numerical': 0.00647693817468106, 'mean_word_length': 2.9843627834245505, 'pattern_counts': {'":': 4, '<': 11, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6289516', 'n_tokens_mistral': 2219, 'n_tokens_neox': 1859, 'n_words': 417}