package main import ( "citrons.xyz/talk/client/client" "citrons.xyz/talk/client/object" "citrons.xyz/talk/client/window" "citrons.xyz/talk/proto" ) type application struct { client.Client quit bool connected bool reconnecting bool authenticated bool uid string cache object.ObjCache windowCache window.WindowCache currentWindow window.Location cmdWindow cmdWindow prompts []window.Prompt } func newApplication(serverAddress string) *application { var app application app.Client = client.New(serverAddress) app.currentWindow = app.cmdWindow.Location() app.cache = object.NewCache(&app) app.windowCache = window.NewCache() app.cmdWindow.info("welcome! type /help for help.") app.cmdWindow.info("connecting to %s", app.Client.Address) return &app } func (a *application) OnConnect() { a.connected = true a.reconnecting = false a.cache = object.NewCache(a) a.windowCache = window.NewCache() a.cmdWindow.info("connected to %s", a.Client.Address) a.pushPrompt(&loginPrompt{}) } func (a *application) OnDisconnect(err error) { a.connected = false a.authenticated = false a.uid = "" a.prompts = nil if !a.reconnecting { a.cmdWindow.err( "disconnected from %s: %s\nreconnecting...", a.Client.Address, err, ) a.reconnecting = true } } func (a *application) OnEvent(cmd proto.Command) { switch cmd.Kind { case "p": cw := a.windowCache.Get(channelLocation {cmd.Target}).(*channelWindow) if cw != nil && len(cmd.Args) > 0 { cw.put(cmd.Args[0]) } case "update": if len(cmd.Args) > 0 { a.cache.Update(cmd.Target, cmd.Args[0]) } case "delete": a.cache.Gone(cmd.Target) } } func (a *application) OnResponse(requestId string, cmd proto.Command) { switch cmd.Kind { case "you-are": if len(cmd.Args) > 0 { a.cmdWindow.info("your name is: %s", cmd.Args[0].Fields[""]) } } } func (a *application) Sub(id string) { a.Request(proto.NewCmd("s", id), func(cmd proto.Command) { if cmd.Kind == "i" && len(cmd.Args) > 0 { a.cache.Update(id, cmd.Args[0]) } }) } func (a *application) Unsub(id string) { a.Request(proto.NewCmd("u", id), nil) } func (a *application) GetInfo(id string, callback func(proto.Command)) { a.Request(proto.NewCmd("i", id), callback) } func (a *application) auth(name string, authCallback func(success bool)) { callback := func(response proto.Command) { switch response.Kind { case "you-are": if len(response.Args) == 0 { authCallback(false) break } me := response.Args[0] a.authenticated = true a.uid = me.Id a.cache.Watch(a.uid) if authCallback != nil { authCallback(true) } case "fail": if len(response.Args) != 0 { a.cmdWindow.err(proto.Strfail(response.Args[0])) } if authCallback != nil { authCallback(false) } } } a.Request(proto.NewCmd("auth", "", proto.Object { "anonymous", "", map[string]string {"": name}, }), callback) } func (a *application) sendUpdate(o proto.Object, cb func(proto.Command)) { a.Request(proto.NewCmd("update", o.Id, o), func(response proto.Command) { if response.Kind == "ok" { a.cache.Update(o.Id, o) } cb(response) }) } func (a *application) lookup( name string, kind string, callback func(*proto.Object, *proto.Fail)) { cb := func(response proto.Command) { switch response.Kind { case "i": if len(response.Args) > 0 { callback(&response.Args[0], nil) } case "fail": if len(response.Args) > 0 { f := proto.Fail(response.Args[0]) callback(nil, &f) } } } o := proto.Object {kind, "", map[string]string {"": name}} a.Request(proto.NewCmd("lookup", "", o), cb) } func (a *application) join(channelName string) { a.lookup(channelName, "channel", func(ch *proto.Object, f *proto.Fail) { if f != nil { a.cmdWindow.err(f.Error()) return } a.Request(proto.NewCmd("join", ch.Id), func(response proto.Command) { switch response.Kind { case "ok": a.currentWindow = channelLocation {id: ch.Id} case "fail": if len(response.Args) > 0 { f := proto.Fail(response.Args[0]) a.cmdWindow.err(f.Error()) } } }) }) } func (a *application) createChannel(name string) { ch := proto.Object {"channel", "", map[string]string {"": name}} a.Request(proto.NewCmd("create", "", ch), func(response proto.Command) { switch response.Kind { case "create": if len(response.Args) > 0 { ch := response.Args[0] a.currentWindow = channelLocation {id: ch.Id} } case "fail": if len(response.Args) > 0 { f := proto.Fail(response.Args[0]) a.cmdWindow.err(f.Error()) } } }) } func (a *application) getNick() string { if !a.authenticated { return "" } u := a.cache.Get(a.uid) if u != nil { return u.Fields[""] } return "" } func (a *application) setNick(newName string) { if !a.authenticated { return } callback := func(response proto.Command) { switch response.Kind { case "fail": if len(response.Args) != 0 { a.cmdWindow.err(proto.Strfail(response.Args[0])) } case "ok": a.cmdWindow.info("your name is: %s", newName) } } a.sendUpdate( proto.Object {"u", a.uid, map[string]string {"": newName}}, callback, ) }