<commit_before>package server

import (
	"crypto/tls"
	"encoding/json"
	"log"
	"net"
	"net/http"
	"strings"

	"github.com/gorilla/websocket"
	"github.com/spf13/viper"

	"github.com/khlieng/dispatch/irc"
	"github.com/khlieng/dispatch/storage"
)

type wsHandler struct {
	ws       *wsConn
	session  *Session
	addr     string
	handlers map[string]func([]byte)
}

func newWSHandler(conn *websocket.Conn, session *Session, r *http.Request) *wsHandler {
	h := &wsHandler{
		ws:      newWSConn(conn),
		session: session,
		addr:    conn.RemoteAddr().String(),
	}
	h.init(r)
	h.initHandlers()
	return h
}

func (h *wsHandler) run() {
	defer h.ws.close()
	go h.ws.send()
	go h.ws.recv()

	for {
		req, ok := <-h.ws.in
		if !ok {
			if h.session != nil {
				h.session.deleteWS(h.addr)
			}
			return
		}

		h.dispatchRequest(req)
	}
}

func (h *wsHandler) dispatchRequest(req WSRequest) {
	if handler, ok := h.handlers[req.Type]; ok {
		handler(req.Data)
	}
}

func (h *wsHandler) init(r *http.Request) {
	h.session.setWS(h.addr, h.ws)

	log.Println(h.addr, "[Session] User ID:", h.session.user.ID, "|",
		h.session.numIRC(), "IRC connections |",
		h.session.numWS(), "WebSocket connections")

	channels := h.session.user.GetChannels()
	params := strings.Split(strings.Trim(r.URL.Query().Get("path"), "/"), "/")

	for _, channel := range channels {
		if len(params) > 1 && channel.Server == params[0] && channel.Name == params[1] {
			continue
		}

		h.session.sendJSON("users", Userlist{
			Server:  channel.Server,
			Channel: channel.Name,
			Users:   channelStore.GetUsers(channel.Server, channel.Name),
		})

		messages, err := h.session.user.GetLastMessages(channel.Server, channel.Name, 25)
		if err == nil && len(messages) > 0 {
			h.session.sendJSON("messages", Messages{
				Server:   channel.Server,
				To:       channel.Name,
				Messages: messages,
			})
		}
	}
}

func (h *wsHandler) connect(b []byte) {
	var data Connect
	json.Unmarshal(b, &data)

	host, port, err := net.SplitHostPort(data.Server)
	if err != nil {
		host = data.Server
	}

	if _, ok := h.session.getIRC(host); !ok {
		log.Println(h.addr, "[IRC] Add server", data.Server)

		i := irc.NewClient(data.Nick, data.Username)
		i.TLS = data.TLS
		i.Realname = data.Realname
		i.HandleNickInUse = createNickInUseHandler(i, h.session)

		if data.Password == "" &&
			viper.GetString("defaults.password") != "" &&
			data.Server == viper.GetString("defaults.address") {
			i.Password = viper.GetString("defaults.password")
		} else {
			i.Password = data.Password
		}

		if cert := h.session.user.GetCertificate(); cert != nil {
			i.TLSConfig = &tls.Config{
				Certificates:       []tls.Certificate{*cert},
				InsecureSkipVerify: !viper.GetBool("verify_client_certificates"),
			}
		}

		h.session.setIRC(host, i)
		i.Connect(data.Server)
		go newIRCHandler(i, h.session).run()

		go h.session.user.AddServer(storage.Server{
			Name:     data.Name,
			Host:     host,
			Port:     port,
			TLS:      data.TLS,
			Password: <PASSWORD>,
			Nick:     data.Nick,
			Username: data.Username,
			Realname: data.Realname,
		})
	} else {
		log.Println(h.addr, "[IRC]", data.Server, "already added")
	}
}

func (h *wsHandler) join(b []byte) {
	var data Join
	json.Unmarshal(b, &data)

	if i, ok := h.session.getIRC(data.Server); ok {
		i.Join(data.Channels...)
	}
}

func (h *wsHandler) part(b []byte) {
	var data Part
	json.Unmarshal(b, &data)

	if i, ok := h.session.getIRC(data.Server); ok {
		i.Part(data.Channels...)
	}
}

func (h *wsHandler) quit(b []byte) {
	var data Quit
	json.Unmarshal(b, &data)

	if i, ok := h.session.getIRC(data.Server); ok {
		log.Println(h.addr, "[IRC] Remove server", data.Server)

		i.Quit()
		h.session.deleteIRC(data.Server)
		channelStore.RemoveUserAll(i.GetNick(), data.Server)
		go h.session.user.RemoveServer(data.Server)
	}
}

func (h *wsHandler) message(b []byte) {
	var data Message
	json.Unmarshal(b, &data)

	if i, ok := h.session.getIRC(data.Server); ok {
		i.Privmsg(data.To, data.Content)
	}
}

func (h *wsHandler) nick(b []byte) {<commit_msg>Log outgoing messages<commit_after>package server

import (
	"crypto/tls"
	"encoding/json"
	"log"
	"net"
	"net/http"
	"strings"

	"github.com/gorilla/websocket"
	"github.com/spf13/viper"

	"github.com/khlieng/dispatch/irc"
	"github.com/khlieng/dispatch/storage"
)

type wsHandler struct {
	ws       *wsConn
	session  *Session
	addr     string
	handlers map[string]func([]byte)
}

func newWSHandler(conn *websocket.Conn, session *Session, r *http.Request) *wsHandler {
	h := &wsHandler{
		ws:      newWSConn(conn),
		session: session,
		addr:    conn.RemoteAddr().String(),
	}
	h.init(r)
	h.initHandlers()
	return h
}

func (h *wsHandler) run() {
	defer h.ws.close()
	go h.ws.send()
	go h.ws.recv()

	for {
		req, ok := <-h.ws.in
		if !ok {
			if h.session != nil {
				h.session.deleteWS(h.addr)
			}
			return
		}

		h.dispatchRequest(req)
	}
}

func (h *wsHandler) dispatchRequest(req WSRequest) {
	if handler, ok := h.handlers[req.Type]; ok {
		handler(req.Data)
	}
}

func (h *wsHandler) init(r *http.Request) {
	h.session.setWS(h.addr, h.ws)

	log.Println(h.addr, "[Session] User ID:", h.session.user.ID, "|",
		h.session.numIRC(), "IRC connections |",
		h.session.numWS(), "WebSocket connections")

	channels := h.session.user.GetChannels()
	params := strings.Split(strings.Trim(r.URL.Query().Get("path"), "/"), "/")

	for _, channel := range channels {
		if len(params) > 1 && channel.Server == params[0] && channel.Name == params[1] {
			continue
		}

		h.session.sendJSON("users", Userlist{
			Server:  channel.Server,
			Channel: channel.Name,
			Users:   channelStore.GetUsers(channel.Server, channel.Name),
		})

		messages, err := h.session.user.GetLastMessages(channel.Server, channel.Name, 25)
		if err == nil && len(messages) > 0 {
			h.session.sendJSON("messages", Messages{
				Server:   channel.Server,
				To:       channel.Name,
				Messages: messages,
			})
		}
	}
}

func (h *wsHandler) connect(b []byte) {
	var data Connect
	json.Unmarshal(b, &data)

	host, port, err := net.SplitHostPort(data.Server)
	if err != nil {
		host = data.Server
	}

	if _, ok := h.session.getIRC(host); !ok {
		log.Println(h.addr, "[IRC] Add server", data.Server)

		i := irc.NewClient(data.Nick, data.Username)
		i.TLS = data.TLS
		i.Realname = data.Realname
		i.HandleNickInUse = createNickInUseHandler(i, h.session)

		if data.Password == "" &&
			viper.GetString("defaults.password") != "" &&
			data.Server == viper.GetString("defaults.address") {
			i.Password = viper.GetString("defaults.password")
		} else {
			i.Password = data.Password
		}

		if cert := h.session.user.GetCertificate(); cert != nil {
			i.TLSConfig = &tls.Config{
				Certificates:       []tls.Certificate{*cert},
				InsecureSkipVerify: !viper.GetBool("verify_client_certificates"),
			}
		}

		h.session.setIRC(host, i)
		i.Connect(data.Server)
		go newIRCHandler(i, h.session).run()

		go h.session.user.AddServer(storage.Server{
			Name:     data.Name,
			Host:     host,
			Port:     port,
			TLS:      data.TLS,
			Password: <PASSWORD>,
			Nick:     data.Nick,
			Username: data.Username,
			Realname: data.Realname,
		})
	} else {
		log.Println(h.addr, "[IRC]", data.Server, "already added")
	}
}

func (h *wsHandler) join(b []byte) {
	var data Join
	json.Unmarshal(b, &data)

	if i, ok := h.session.getIRC(data.Server); ok {
		i.Join(data.Channels...)
	}
}

func (h *wsHandler) part(b []byte) {
	var data Part
	json.Unmarshal(b, &data)

	if i, ok := h.session.getIRC(data.Server); ok {
		i.Part(data.Channels...)
	}
}

func (h *wsHandler) quit(b []byte) {
	var data Quit
	json.Unmarshal(b, &data)

	if i, ok := h.session.getIRC(data.Server); ok {
		log.Println(h.addr, "[IRC] Remove server", data.Server)

		i.Quit()
		h.session.deleteIRC(data.Server)
		channelStore.RemoveUserAll(i.GetNick(), data.Server)
		go h.session.user.RemoveServer(data.Server)
	}
}

func (h *wsHandler) message(b []byte) {
	var data Message
	json.Unmarshal(b, &data)

	if i, ok := h.session.getIRC(data.Server); ok {
		i.Privmsg(data.To, data.Content)
		go h.session.user.LogMessage(data.Server, i.GetNick(), data.To, data.Content)
	}
}

func (h *wsHandler) nick(b []byte) {
{'fraction_non_alphanumeric': 0.17073766487542746, 'fraction_numerical': 0.0019540791402051783, 'mean_word_length': 3.4288804759329365, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, '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': '4303835', 'n_tokens_mistral': 3421, 'n_tokens_neox': 3127, 'n_words': 621}