package main import ( "code.google.com/p/go.net/websocket" "fmt" "github.com/bitly/go-notify" "github.com/kballard/goirc/irc" "html/template" "log" "math/rand" "net/http" "strings" "sync" "sync/atomic" "time") const ( channel = "#comicchat") var ( nusers int32 = 0) type WebClientMessage struct { Type string Message string} const ( // fresh connection ClientNew int32 = iota // everything ok - ws and irc connected ClientOk // someone closed - kill everything ClientClosed) // a websocket connection to irctype WebClient struct { mu sync.Mutex remote string nick string status int32 config irc.Config irc irc.SafeConn ircquit chan bool ws *websocket.Conn} func NewWebClient(remote string, ws *websocket.Conn) *WebClient { nick := fmt.Sprintf("comicchat%5.5d", rand.Intn(99999)) wc := &WebClient{ remote: remote, nick: nick, status: ClientNew, config: irc.Config{ Host: "chat.freenode.net", Nick: nick, User: "comicchat", RealName: "Comic Chat", }, ws: ws, } wc.config.Init = func(hr irc.HandlerRegistry) { hr.AddHandler(irc.CONNECTED, wc.loggedin) } return wc} func (w WebClient) String() string { return fmt.Sprintf("%s %s", w.remote, w.nick)} func (w *WebClient) GetStatus() int32 { return atomic.LoadInt32(&w.status)} func (w *WebClient) SetStatus(s int32) int32 { return atomic.SwapInt32(&w.status, s)} // called when irc client connectsfunc (w *WebClient) loggedin(conn *irc.Conn, line irc.Line) { conn.Join([]string{"#comicchat"}, nil)} func (w *WebClient) Send(typ, msg string) error { if w.GetStatus() != ClientClosed { var m WebClientMessage w.mu.Lock() defer w.mu.Unlock() m.Type = typ m.Message = msg if err := websocket.JSON.Send(w.ws, &m); err != nil { return err } } return nil} // websocket read handlerfunc (w *WebClient) reader() { var err error w.mu.Lock() w.irc, err = irc.Connect(w.config) if err != nil { log.Printf("%s %s", w, err) w.ws.Close() w.mu.Unlock() return } w.mu.Unlock() w.Send("connected", fmt.Sprintf("%d", atomic.LoadInt32(&nusers))) defer func() { w.irc.Quit("disconnected") }() for w.GetStatus() != ClientClosed { var m WebClientMessage err = websocket.JSON.Receive(w.ws, &m) if err != nil { log.Printf("%s read: %s", w, err) w.SetStatus(ClientClosed) continue } if w.irc == nil { continue } switch m.Type { case "nick": w.irc.Nick(m.Message) case "privmsg": w.irc.Privmsg("#comicchat", m.Message) case "action": w.irc.Action("#comicchat", m.Message) case "connect": } }} // websocket write handlerfunc (w *WebClient) writer() { imgurlchan := make(chan interface{}) notify.Start("newimage", imgurlchan) defer notify.Stop("newimage", imgurlchan) for w.GetStatus() != ClientClosed { select { case url := <-imgurlchan: if err := w.Send("newimage", url.(string)); err != nil { log.Printf("%s closed: %s", w, err) w.SetStatus(ClientClosed) } case <-time.After(30 * time.Second): if err := w.Send("ping", fmt.Sprintf("%d", time.Now().UnixNano())); err != nil { log.Printf("%s closed: %s", w, err) w.SetStatus(ClientClosed) } } }} func dohttp() { http.HandleFunc("/", indexhandler) http.HandleFunc("/new", websockethandler) http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/")))) http.Handle("/comic/", http.StripPrefix("/comic/", http.FileServer(http.Dir("comic/")))) if err := http.ListenAndServe(":8899", nil); err != nil { log.Fatal("ListenAndServe:", err) }} type Page struct { Faces []string} func indexhandler(w http.ResponseWriter, r *http.Request) { //create a new template indextmpl := template.Must(template.New("index.tpl").ParseFiles("template/index.tpl")) page := Page{ Faces: facekeys, } if err := indextmpl.Execute(w, page); err != nil { log.Printf("%s", err) }} func websockethandler(w http.ResponseWriter, r *http.Request) { // get remote client's address. we may be behind a proxy (nginx) rem := r.RemoteAddr if strings.Split(rem, ":")[0] == "127.0.0.1" { rem = r.Header.Get("X-Real-IP") } websocket.Handler(func(ws *websocket.Conn) { wc := NewWebClient(rem, ws) log.Printf("%s connected", wc) atomic.AddInt32(&nusers, 1) defer atomic.AddInt32(&nusers, -1) go wc.writer() wc.reader() log.Printf("%s disconnected", wc) }).ServeHTTP(w, r)}
package main
import (
"code.google.com/p/go.net/websocket"
"fmt"
"github.com/bitly/go-notify"
"github.com/kballard/goirc/irc"
"html/template"
"log"
"math/rand"
"net/http"
"strings"
"sync"
"sync/atomic"
"time"
)
const (
channel = "#comicchat"
)
var (
nusers int32 = 0
)
type WebClientMessage struct {
Type string
Message string
}
const (
// fresh connection
ClientNew int32 = iota
// everything ok - ws and irc connected
ClientOk
// someone closed - kill everything
ClientClosed
)
// a websocket connection to irc
type WebClient struct {
mu sync.Mutex
remote string
nick string
status int32
config irc.Config
irc irc.SafeConn
ircquit chan bool
ws *websocket.Conn
}
func NewWebClient(remote string, ws *websocket.Conn) *WebClient {
nick := fmt.Sprintf("comicchat%5.5d", rand.Intn(99999))
wc := &WebClient{
remote: remote,
nick: nick,
status: ClientNew,
config: irc.Config{
Host: "chat.freenode.net",
Nick: nick,
User: "comicchat",
RealName: "Comic Chat",
},
ws: ws,
}
wc.config.Init = func(hr irc.HandlerRegistry) {
hr.AddHandler(irc.CONNECTED, wc.loggedin)
}
return wc
}
func (w WebClient) String() string {
return fmt.Sprintf("%s %s", w.remote, w.nick)
}
func (w *WebClient) GetStatus() int32 {
return atomic.LoadInt32(&w.status)
}
func (w *WebClient) SetStatus(s int32) int32 {
return atomic.SwapInt32(&w.status, s)
}
// called when irc client connects
func (w *WebClient) loggedin(conn *irc.Conn, line irc.Line) {
conn.Join([]string{"#comicchat"}, nil)
}
func (w *WebClient) Send(typ, msg string) error {
if w.GetStatus() != ClientClosed {
var m WebClientMessage
w.mu.Lock()
defer w.mu.Unlock()
m.Type = typ
m.Message = msg
if err := websocket.JSON.Send(w.ws, &m); err != nil {
return err
}
}
return nil
}
// websocket read handler
func (w *WebClient) reader() {
var err error
w.mu.Lock()
w.irc, err = irc.Connect(w.config)
if err != nil {
log.Printf("%s %s", w, err)
w.ws.Close()
w.mu.Unlock()
return
}
w.mu.Unlock()
w.Send("connected", fmt.Sprintf("%d", atomic.LoadInt32(&nusers)))
defer func() {
w.irc.Quit("disconnected")
}()
for w.GetStatus() != ClientClosed {
var m WebClientMessage
err = websocket.JSON.Receive(w.ws, &m)
if err != nil {
log.Printf("%s read: %s", w, err)
w.SetStatus(ClientClosed)
continue
}
if w.irc == nil {
continue
}
switch m.Type {
case "nick":
w.irc.Nick(m.Message)
case "privmsg":
w.irc.Privmsg("#comicchat", m.Message)
case "action":
w.irc.Action("#comicchat", m.Message)
case "connect":
}
}
}
// websocket write handler
func (w *WebClient) writer() {
imgurlchan := make(chan interface{})
notify.Start("newimage", imgurlchan)
defer notify.Stop("newimage", imgurlchan)
for w.GetStatus() != ClientClosed {
select {
case url := <-imgurlchan:
if err := w.Send("newimage", url.(string)); err != nil {
log.Printf("%s closed: %s", w, err)
w.SetStatus(ClientClosed)
}
case <-time.After(30 * time.Second):
if err := w.Send("ping", fmt.Sprintf("%d", time.Now().UnixNano())); err != nil {
log.Printf("%s closed: %s", w, err)
w.SetStatus(ClientClosed)
}
}
}
}
func dohttp() {
http.HandleFunc("/", indexhandler)
http.HandleFunc("/new", websockethandler)
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))
http.Handle("/comic/", http.StripPrefix("/comic/", http.FileServer(http.Dir("comic/"))))
if err := http.ListenAndServe(":8899", nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}
type Page struct {
Faces []string
}
func indexhandler(w http.ResponseWriter, r *http.Request) {
//create a new template
indextmpl := template.Must(template.New("index.tpl").ParseFiles("template/index.tpl"))
page := Page{
Faces: facekeys,
}
if err := indextmpl.Execute(w, page); err != nil {
log.Printf("%s", err)
}
}
func websockethandler(w http.ResponseWriter, r *http.Request) {
// get remote client's address. we may be behind a proxy (nginx)
rem := r.RemoteAddr
if strings.Split(rem, ":")[0] == "127.0.0.1" {
rem = r.Header.Get("X-Real-IP")
}
websocket.Handler(func(ws *websocket.Conn) {
wc := NewWebClient(rem, ws)
log.Printf("%s connected", wc)
atomic.AddInt32(&nusers, 1)
defer atomic.AddInt32(&nusers, -1)
go wc.writer()
wc.reader()
log.Printf("%s disconnected", wc)
}).ServeHTTP(w, r)
}