<commit_before>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !appengine

package main

import (
	"bufio"
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"sync"

	"code.google.com/p/go.net/websocket"
)

const msgLimit = 1000 // max number of messages to send per session

var uniq = make(chan int) // a source of numbers for naming temporary files

func init() {
	playEnabled = true // instruct code.go to include "Run" buttons

	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	http.Handle("/socket", websocket.Handler(socketHandler))
}

// Message is the wire format for the websocket connection to the browser.
// It is used for both sending output messages and receiving commands, as
// distinguished by the Kind field.
type Message struct {
	Id   string // client-provided unique id for the process
	Kind string // in: "run", "kill" out: "stdout", "stderr", "end"
	Body string
}

// socketHandler handles the websocket connection for given present session.
// It constructs a new Client and handles transcoding Messages to and from JSON
// format, sending and receiving those messages on the Client's in and out
// channels.
func socketHandler(conn *websocket.Conn) {
	in, out := make(chan *Message), make(chan *Message)
	c := &Client{
		proc: make(map[string]*Process),
		in:   in,
		out:  out,
	}
	go c.loop()

	dec := json.NewDecoder(conn)
	enc := json.NewEncoder(conn)
	errc := make(chan error, 1)
	go func() {
		for {
			m := new(Message)
			if err := dec.Decode(m); err != nil {
				errc <- err
				close(in)
				return
			}
			in <- m
		}
	}()
	go func() {
		counts := make(map[string]int)
		for {
			m := <-out
			switch c := counts[m.Id]; {
			case m.Kind == "end" || c < msgLimit:
				if err := enc.Encode(m); err != nil {
					errc <- err
					return
				}
			case c == msgLimit:
				// Kill it.
				in <- &Message{Id: m.Id, Kind: "end"}
			}
			counts[m.Id]++
		}
	}()
	err := <-errc
	if err != nil && err != io.EOF {
		log.Println(err)
	}
}

// Client represents a connected present client.
// It manages any processes being compiled and run for the client.
type Client struct {
	sync.Mutex<commit_msg>go.talks/present: kill running processes when client disconnects<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !appengine

package main

import (
	"bufio"
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"sync"

	"code.google.com/p/go.net/websocket"
)

const msgLimit = 1000 // max number of messages to send per session

var uniq = make(chan int) // a source of numbers for naming temporary files

func init() {
	playEnabled = true // instruct code.go to include "Run" buttons

	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	http.Handle("/socket", websocket.Handler(socketHandler))
}

// Message is the wire format for the websocket connection to the browser.
// It is used for both sending output messages and receiving commands, as
// distinguished by the Kind field.
type Message struct {
	Id   string // client-provided unique id for the process
	Kind string // in: "run", "kill" out: "stdout", "stderr", "end"
	Body string
}

// socketHandler handles the websocket connection for given present session.
// It constructs a new Client and handles transcoding Messages to and from JSON
// format, sending and receiving those messages on the Client's in and out
// channels.
func socketHandler(conn *websocket.Conn) {
	in, out := make(chan *Message), make(chan *Message)
	c := &Client{
		proc: make(map[string]*Process),
		in:   in,
		out:  out,
	}
	go c.loop()

	dec := json.NewDecoder(conn)
	enc := json.NewEncoder(conn)
	errc := make(chan error, 1)
	go func() {
		for {
			m := new(Message)
			if err := dec.Decode(m); err != nil {
				errc <- err
				close(in)
				return
			}
			in <- m
		}
	}()
	go func() {
		counts := make(map[string]int)
		for {
			m := <-out
			switch c := counts[m.Id]; {
			case m.Kind == "end" || c < msgLimit:
				if err := enc.Encode(m); err != nil {
					errc <- err
					return
				}
			case c == msgLimit:
				// Kill it.
				in <- &Message{Id: m.Id, Kind: "end"}
			}
			counts[m.Id]++
		}
	}()
	err := <-errc
	if err != nil && err != io.EOF {
		log.Println(err)
	}

	// Kill any running processes.
	c.Lock()
	for _, p := range c.proc {
		p.kill()
	}
	c.Unlock()
}

// Client represents a connected present client.
// It manages any processes being compiled and run for the client.
type Client struct {
	sync.Mutex
{'fraction_non_alphanumeric': 0.1357172731074864, 'fraction_numerical': 0.004182350480970306, 'mean_word_length': 2.914075286415712, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 3, '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': '3780164', 'n_tokens_mistral': 1797, 'n_tokens_neox': 1615, 'n_words': 578}