Log direct messages and keep track of open direct message tabs
This commit is contained in:
parent
e97bb519ed
commit
8305dd561d
File diff suppressed because one or more lines are too long
@ -29,6 +29,13 @@ function loadState({ store }, env) {
|
||||
});
|
||||
}
|
||||
|
||||
if (env.openDMs) {
|
||||
store.dispatch({
|
||||
type: 'PRIVATE_CHATS',
|
||||
privateChats: env.openDMs
|
||||
});
|
||||
}
|
||||
|
||||
if (env.users) {
|
||||
store.dispatch({
|
||||
type: socketActions.USERS,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Cookie from 'js-cookie';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { getSelectedTab } from 'state/tab';
|
||||
import { isChannel, stringifyTab } from 'utils';
|
||||
import { stringifyTab } from 'utils';
|
||||
import { observe } from 'utils/observe';
|
||||
|
||||
const saveTab = debounce(
|
||||
@ -11,7 +11,7 @@ const saveTab = debounce(
|
||||
|
||||
export default function storage({ store }) {
|
||||
observe(store, getSelectedTab, tab => {
|
||||
if (isChannel(tab) || (tab.server && !tab.name)) {
|
||||
if (tab.server) {
|
||||
saveTab(tab);
|
||||
}
|
||||
});
|
||||
|
@ -26,6 +26,7 @@ export const CLOSE_MODAL = 'CLOSE_MODAL';
|
||||
|
||||
export const CLOSE_PRIVATE_CHAT = 'CLOSE_PRIVATE_CHAT';
|
||||
export const OPEN_PRIVATE_CHAT = 'OPEN_PRIVATE_CHAT';
|
||||
export const PRIVATE_CHATS = 'PRIVATE_CHATS';
|
||||
|
||||
export const SEARCH_MESSAGES = 'SEARCH_MESSAGES';
|
||||
export const TOGGLE_SEARCH = 'TOGGLE_SEARCH';
|
||||
|
@ -30,6 +30,16 @@ export default createReducer(
|
||||
}
|
||||
},
|
||||
|
||||
[actions.PRIVATE_CHATS](state, { privateChats }) {
|
||||
privateChats.forEach(({ server, name }) => {
|
||||
if (!state[server]) {
|
||||
state[server] = [];
|
||||
}
|
||||
|
||||
state[server].push(name);
|
||||
});
|
||||
},
|
||||
|
||||
[actions.socket.PM](state, action) {
|
||||
if (action.from.indexOf('.') === -1) {
|
||||
open(state, action.server, action.from);
|
||||
@ -46,7 +56,11 @@ export function openPrivateChat(server, nick) {
|
||||
return {
|
||||
type: actions.OPEN_PRIVATE_CHAT,
|
||||
server,
|
||||
nick
|
||||
nick,
|
||||
socket: {
|
||||
type: 'open_dm',
|
||||
data: { server, name: nick }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -55,7 +69,11 @@ export function closePrivateChat(server, nick) {
|
||||
dispatch({
|
||||
type: actions.CLOSE_PRIVATE_CHAT,
|
||||
server,
|
||||
nick
|
||||
nick,
|
||||
socket: {
|
||||
type: 'close_dm',
|
||||
data: { server, name: nick }
|
||||
}
|
||||
});
|
||||
dispatch(updateSelection());
|
||||
};
|
||||
|
@ -31,6 +31,7 @@ type indexData struct {
|
||||
Defaults *config.Defaults
|
||||
Servers []Server
|
||||
Channels []*storage.Channel
|
||||
OpenDMs []storage.Tab
|
||||
HexIP bool
|
||||
Version dispatchVersion
|
||||
|
||||
@ -43,7 +44,7 @@ type indexData struct {
|
||||
Messages *Messages
|
||||
}
|
||||
|
||||
func (d *Dispatch) getIndexData(r *http.Request, path string, state *State) *indexData {
|
||||
func (d *Dispatch) getIndexData(r *http.Request, state *State) *indexData {
|
||||
cfg := d.Config()
|
||||
|
||||
data := indexData{
|
||||
@ -98,35 +99,37 @@ func (d *Dispatch) getIndexData(r *http.Request, path string, state *State) *ind
|
||||
}
|
||||
data.Channels = channels
|
||||
|
||||
server, channel := getTabFromPath(path)
|
||||
if isInChannel(channels, server, channel) {
|
||||
data.addUsersAndMessages(server, channel, state)
|
||||
return &data
|
||||
openDMs, err := state.user.GetOpenDMs()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
data.OpenDMs = openDMs
|
||||
|
||||
server, channel = parseTabCookie(r, path)
|
||||
if isInChannel(channels, server, channel) {
|
||||
data.addUsersAndMessages(server, channel, state)
|
||||
tab, err := tabFromRequest(r)
|
||||
if err == nil && hasTab(channels, openDMs, tab.Server, tab.Name) {
|
||||
data.addUsersAndMessages(tab.Server, tab.Name, state)
|
||||
}
|
||||
|
||||
return &data
|
||||
}
|
||||
|
||||
func (d *indexData) addUsersAndMessages(server, channel string, state *State) {
|
||||
users := channelStore.GetUsers(server, channel)
|
||||
func (d *indexData) addUsersAndMessages(server, name string, state *State) {
|
||||
if isChannel(name) {
|
||||
users := channelStore.GetUsers(server, name)
|
||||
if len(users) > 0 {
|
||||
d.Users = &Userlist{
|
||||
Server: server,
|
||||
Channel: channel,
|
||||
Channel: name,
|
||||
Users: users,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
messages, hasMore, err := state.user.GetLastMessages(server, channel, 50)
|
||||
messages, hasMore, err := state.user.GetLastMessages(server, name, 50)
|
||||
if err == nil && len(messages) > 0 {
|
||||
m := Messages{
|
||||
Server: server,
|
||||
To: channel,
|
||||
To: name,
|
||||
Messages: messages,
|
||||
}
|
||||
|
||||
@ -138,10 +141,16 @@ func (d *indexData) addUsersAndMessages(server, channel string, state *State) {
|
||||
}
|
||||
}
|
||||
|
||||
func isInChannel(channels []*storage.Channel, server, channel string) bool {
|
||||
if channel != "" {
|
||||
func hasTab(channels []*storage.Channel, openDMs []storage.Tab, server, name string) bool {
|
||||
if name != "" {
|
||||
for _, ch := range channels {
|
||||
if server == ch.Server && channel == ch.Name {
|
||||
if server == ch.Server && name == ch.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for _, tab := range openDMs {
|
||||
if server == tab.Server && name == tab.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -149,30 +158,52 @@ func isInChannel(channels []*storage.Channel, server, channel string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func getTabFromPath(rawPath string) (string, string) {
|
||||
path := strings.Split(strings.Trim(rawPath, "/"), "/")
|
||||
if len(path) >= 2 {
|
||||
name, err := url.PathUnescape(path[len(path)-1])
|
||||
if err == nil && isChannel(name) {
|
||||
return path[len(path)-2], name
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
func tabFromRequest(r *http.Request) (Tab, error) {
|
||||
tab := Tab{}
|
||||
|
||||
var path string
|
||||
if strings.HasPrefix(r.URL.Path, "/ws") {
|
||||
path = r.URL.EscapedPath()[3:]
|
||||
} else {
|
||||
referer, err := url.Parse(r.Referer())
|
||||
if err != nil {
|
||||
return tab, err
|
||||
}
|
||||
|
||||
path = referer.EscapedPath()
|
||||
}
|
||||
|
||||
func parseTabCookie(r *http.Request, path string) (string, string) {
|
||||
if path == "/" {
|
||||
cookie, err := r.Cookie("tab")
|
||||
if err == nil {
|
||||
v, err := url.PathUnescape(cookie.Value)
|
||||
if err == nil {
|
||||
tab := strings.SplitN(v, ";", 2)
|
||||
if err != nil {
|
||||
return tab, err
|
||||
}
|
||||
|
||||
if len(tab) == 2 && isChannel(tab[1]) {
|
||||
return tab[0], tab[1]
|
||||
v, err := url.PathUnescape(cookie.Value)
|
||||
if err != nil {
|
||||
return tab, err
|
||||
}
|
||||
|
||||
parts := strings.SplitN(v, ";", 2)
|
||||
if len(parts) == 2 {
|
||||
tab.Server = parts[0]
|
||||
tab.Name = parts[1]
|
||||
}
|
||||
} else {
|
||||
parts := strings.Split(strings.Trim(path, "/"), "/")
|
||||
if len(parts) > 0 && len(parts) < 3 {
|
||||
if len(parts) == 2 {
|
||||
name, err := url.PathUnescape(parts[1])
|
||||
if err != nil {
|
||||
return tab, err
|
||||
}
|
||||
|
||||
tab.Name = name
|
||||
}
|
||||
|
||||
tab.Server = parts[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
|
||||
return tab, nil
|
||||
}
|
||||
|
@ -104,6 +104,29 @@ func easyjson7e607aefDecodeGithubComKhliengDispatchServer(in *jlexer.Lexer, out
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "openDMs":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.OpenDMs = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.OpenDMs == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.OpenDMs = make([]storage.Tab, 0, 2)
|
||||
} else {
|
||||
out.OpenDMs = []storage.Tab{}
|
||||
}
|
||||
} else {
|
||||
out.OpenDMs = (out.OpenDMs)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v3 storage.Tab
|
||||
easyjson7e607aefDecodeGithubComKhliengDispatchStorage1(in, &v3)
|
||||
out.OpenDMs = append(out.OpenDMs, v3)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "hexIP":
|
||||
out.HexIP = bool(in.Bool())
|
||||
case "version":
|
||||
@ -176,11 +199,11 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchServer(out *jwriter.Writer, i
|
||||
}
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v3, v4 := range in.Servers {
|
||||
if v3 > 0 {
|
||||
for v4, v5 := range in.Servers {
|
||||
if v4 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Raw((v4).MarshalJSON())
|
||||
out.Raw((v5).MarshalJSON())
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
@ -195,19 +218,38 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchServer(out *jwriter.Writer, i
|
||||
}
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v5, v6 := range in.Channels {
|
||||
if v5 > 0 {
|
||||
for v6, v7 := range in.Channels {
|
||||
if v6 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
if v6 == nil {
|
||||
if v7 == nil {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
easyjson7e607aefEncodeGithubComKhliengDispatchStorage(out, *v6)
|
||||
easyjson7e607aefEncodeGithubComKhliengDispatchStorage(out, *v7)
|
||||
}
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
if len(in.OpenDMs) != 0 {
|
||||
const prefix string = ",\"openDMs\":"
|
||||
if first {
|
||||
first = false
|
||||
out.RawString(prefix[1:])
|
||||
} else {
|
||||
out.RawString(prefix)
|
||||
}
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v8, v9 := range in.OpenDMs {
|
||||
if v8 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
easyjson7e607aefEncodeGithubComKhliengDispatchStorage1(out, v9)
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
if in.HexIP {
|
||||
const prefix string = ",\"hexIP\":"
|
||||
if first {
|
||||
@ -284,6 +326,61 @@ func (v *indexData) UnmarshalJSON(data []byte) error {
|
||||
func (v *indexData) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson7e607aefDecodeGithubComKhliengDispatchServer(l, v)
|
||||
}
|
||||
func easyjson7e607aefDecodeGithubComKhliengDispatchStorage1(in *jlexer.Lexer, out *storage.Tab) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeFieldName(false)
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "server":
|
||||
out.Server = string(in.String())
|
||||
case "name":
|
||||
out.Name = string(in.String())
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson7e607aefEncodeGithubComKhliengDispatchStorage1(out *jwriter.Writer, in storage.Tab) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
if in.Server != "" {
|
||||
const prefix string = ",\"server\":"
|
||||
first = false
|
||||
out.RawString(prefix[1:])
|
||||
out.String(string(in.Server))
|
||||
}
|
||||
if in.Name != "" {
|
||||
const prefix string = ",\"name\":"
|
||||
if first {
|
||||
first = false
|
||||
out.RawString(prefix[1:])
|
||||
} else {
|
||||
out.RawString(prefix)
|
||||
}
|
||||
out.String(string(in.Name))
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
func easyjson7e607aefDecodeGithubComKhliengDispatchStorage(in *jlexer.Lexer, out *storage.Channel) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
@ -392,9 +489,9 @@ func easyjson7e607aefDecodeGithubComKhliengDispatchConfig(in *jlexer.Lexer, out
|
||||
out.Channels = (out.Channels)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v7 string
|
||||
v7 = string(in.String())
|
||||
out.Channels = append(out.Channels, v7)
|
||||
var v10 string
|
||||
v10 = string(in.String())
|
||||
out.Channels = append(out.Channels, v10)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
@ -457,11 +554,11 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchConfig(out *jwriter.Writer, i
|
||||
}
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v8, v9 := range in.Channels {
|
||||
if v8 > 0 {
|
||||
for v11, v12 := range in.Channels {
|
||||
if v11 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v9))
|
||||
out.String(string(v12))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
@ -640,9 +737,9 @@ func easyjson7e607aefDecodeGithubComKhliengDispatchServer2(in *jlexer.Lexer, out
|
||||
out.Channels = (out.Channels)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v10 string
|
||||
v10 = string(in.String())
|
||||
out.Channels = append(out.Channels, v10)
|
||||
var v13 string
|
||||
v13 = string(in.String())
|
||||
out.Channels = append(out.Channels, v13)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
@ -705,11 +802,11 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchServer2(out *jwriter.Writer,
|
||||
}
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v11, v12 := range in.Channels {
|
||||
if v11 > 0 {
|
||||
for v14, v15 := range in.Channels {
|
||||
if v14 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v12))
|
||||
out.String(string(v15))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
|
@ -1,47 +1,60 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/khlieng/dispatch/storage"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetTabFromPath(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
expectedServer string
|
||||
expectedChannel string
|
||||
input *http.Request
|
||||
expectedTab Tab
|
||||
}{
|
||||
{
|
||||
"/chat.freenode.net/%23r%2Fstuff%2F/",
|
||||
"chat.freenode.net",
|
||||
"#r/stuff/",
|
||||
&http.Request{
|
||||
URL: &url.URL{Path: "/init"},
|
||||
Header: http.Header{"Referer": []string{"/chat.freenode.net/%23r%2Fstuff%2F"}},
|
||||
},
|
||||
Tab{storage.Tab{Server: "chat.freenode.net", Name: "#r/stuff/"}},
|
||||
}, {
|
||||
"/chat.freenode.net/%23r%2Fstuff%2F",
|
||||
"chat.freenode.net",
|
||||
"#r/stuff/",
|
||||
&http.Request{
|
||||
URL: &url.URL{Path: "/init"},
|
||||
Header: http.Header{"Referer": []string{"/chat.freenode.net/%23r%2Fstuff"}},
|
||||
},
|
||||
Tab{storage.Tab{Server: "chat.freenode.net", Name: "#r/stuff"}},
|
||||
}, {
|
||||
"/chat.freenode.net/%23r%2Fstuff",
|
||||
"chat.freenode.net",
|
||||
"#r/stuff",
|
||||
&http.Request{
|
||||
URL: &url.URL{Path: "/init"},
|
||||
Header: http.Header{"Referer": []string{"/chat.freenode.net/%23stuff"}},
|
||||
},
|
||||
Tab{storage.Tab{Server: "chat.freenode.net", Name: "#stuff"}},
|
||||
}, {
|
||||
"/chat.freenode.net/%23stuff",
|
||||
"chat.freenode.net",
|
||||
"#stuff",
|
||||
&http.Request{
|
||||
URL: &url.URL{Path: "/init"},
|
||||
Header: http.Header{"Referer": []string{"/chat.freenode.net/stuff"}},
|
||||
},
|
||||
Tab{storage.Tab{Server: "chat.freenode.net", Name: "stuff"}},
|
||||
}, {
|
||||
"/chat.freenode.net/%23stuff/cake",
|
||||
"",
|
||||
"",
|
||||
&http.Request{
|
||||
URL: &url.URL{Path: "/init"},
|
||||
Header: http.Header{"Referer": []string{"/data/chat.freenode.net/%23apples"}},
|
||||
},
|
||||
Tab{},
|
||||
}, {
|
||||
"/data/chat.freenode.net/%23apples",
|
||||
"chat.freenode.net",
|
||||
"#apples",
|
||||
&http.Request{
|
||||
URL: &url.URL{Path: "/ws/chat.freenode.net"},
|
||||
},
|
||||
Tab{storage.Tab{Server: "chat.freenode.net"}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
server, channel := getTabFromPath(tc.input)
|
||||
assert.Equal(t, tc.expectedServer, server)
|
||||
assert.Equal(t, tc.expectedChannel, channel)
|
||||
tab, err := tabFromRequest(tc.input)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.expectedTab, tab)
|
||||
}
|
||||
}
|
||||
|
@ -169,17 +169,21 @@ func (i *ircHandler) message(msg *irc.Message) {
|
||||
From: msg.Nick,
|
||||
Content: msg.LastParam(),
|
||||
}
|
||||
target := msg.Params[0]
|
||||
|
||||
if msg.Params[0] == i.client.GetNick() {
|
||||
if target == i.client.GetNick() {
|
||||
i.state.sendJSON("pm", message)
|
||||
i.state.user.AddOpenDM(i.client.Host, message.From)
|
||||
|
||||
target = message.From
|
||||
} else {
|
||||
message.To = msg.Params[0]
|
||||
message.To = target
|
||||
i.state.sendJSON("message", message)
|
||||
}
|
||||
|
||||
if msg.Params[0] != "*" {
|
||||
if target != "*" {
|
||||
go i.state.user.LogMessage(message.ID,
|
||||
i.client.Host, msg.Nick, msg.Params[0], msg.LastParam())
|
||||
i.client.Host, msg.Nick, target, msg.LastParam())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,3 +221,7 @@ type ChannelForward struct {
|
||||
Old string
|
||||
New string
|
||||
}
|
||||
|
||||
type Tab struct {
|
||||
storage.Tab
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,6 @@ package server
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -163,14 +162,8 @@ func (d *Dispatch) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if r.URL.Path == "/init" {
|
||||
referer, err := url.Parse(r.Header.Get("Referer"))
|
||||
if err != nil {
|
||||
fail(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
state := d.handleAuth(w, r, true, true)
|
||||
data := d.getIndexData(r, referer.EscapedPath(), state)
|
||||
data := d.getIndexData(r, state)
|
||||
|
||||
writeJSON(w, r, data)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/ws") {
|
||||
|
@ -68,17 +68,15 @@ func (h *wsHandler) init(r *http.Request) {
|
||||
h.state.numIRC(), "IRC connections |",
|
||||
h.state.numWS(), "WebSocket connections")
|
||||
|
||||
tab, err := tabFromRequest(r)
|
||||
|
||||
channels, err := h.state.user.GetChannels()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
path := r.URL.EscapedPath()
|
||||
pathServer, pathChannel := getTabFromPath(path)
|
||||
cookieServer, cookieChannel := parseTabCookie(r, path[3:])
|
||||
|
||||
for _, channel := range channels {
|
||||
if (channel.Server == pathServer && channel.Name == pathChannel) ||
|
||||
(channel.Server == cookieServer && channel.Name == cookieChannel) {
|
||||
if channel.Server == tab.Server && channel.Name == tab.Name {
|
||||
// Userlist and messages for this channel gets embedded in the index page
|
||||
continue
|
||||
}
|
||||
@ -91,6 +89,19 @@ func (h *wsHandler) init(r *http.Request) {
|
||||
|
||||
h.state.sendLastMessages(channel.Server, channel.Name, 50)
|
||||
}
|
||||
|
||||
openDMs, err := h.state.user.GetOpenDMs()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
for _, openDM := range openDMs {
|
||||
if openDM.Server == tab.Server && openDM.Name == tab.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
h.state.sendLastMessages(openDM.Server, openDM.Name, 50)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *wsHandler) connect(b []byte) {
|
||||
@ -306,6 +317,21 @@ func (h *wsHandler) channelSearch(b []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *wsHandler) openDM(b []byte) {
|
||||
var data Tab
|
||||
data.UnmarshalJSON(b)
|
||||
|
||||
h.state.sendLastMessages(data.Server, data.Name, 50)
|
||||
h.state.user.AddOpenDM(data.Server, data.Name)
|
||||
}
|
||||
|
||||
func (h *wsHandler) closeDM(b []byte) {
|
||||
var data Tab
|
||||
data.UnmarshalJSON(b)
|
||||
|
||||
h.state.user.RemoveOpenDM(data.Server, data.Name)
|
||||
}
|
||||
|
||||
func (h *wsHandler) initHandlers() {
|
||||
h.handlers = map[string]func([]byte){
|
||||
"connect": h.connect,
|
||||
@ -327,6 +353,8 @@ func (h *wsHandler) initHandlers() {
|
||||
"set_server_name": h.setServerName,
|
||||
"settings_set": h.setSettings,
|
||||
"channel_search": h.channelSearch,
|
||||
"open_dm": h.openDM,
|
||||
"close_dm": h.closeDM,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ var (
|
||||
bucketUsers = []byte("Users")
|
||||
bucketServers = []byte("Servers")
|
||||
bucketChannels = []byte("Channels")
|
||||
bucketOpenDMs = []byte("OpenDMs")
|
||||
bucketMessages = []byte("Messages")
|
||||
bucketSessions = []byte("Sessions")
|
||||
)
|
||||
@ -34,6 +35,7 @@ func New(path string) (*BoltStore, error) {
|
||||
tx.CreateBucketIfNotExists(bucketUsers)
|
||||
tx.CreateBucketIfNotExists(bucketServers)
|
||||
tx.CreateBucketIfNotExists(bucketChannels)
|
||||
tx.CreateBucketIfNotExists(bucketOpenDMs)
|
||||
tx.CreateBucketIfNotExists(bucketMessages)
|
||||
tx.CreateBucketIfNotExists(bucketSessions)
|
||||
return nil
|
||||
@ -168,6 +170,13 @@ func (s *BoltStore) RemoveServer(user *storage.User, address string) error {
|
||||
b.Delete(k)
|
||||
}
|
||||
|
||||
b = tx.Bucket(bucketOpenDMs)
|
||||
c = b.Cursor()
|
||||
|
||||
for k, _ := c.Seek(serverID); bytes.HasPrefix(k, serverID); k, _ = c.Next() {
|
||||
b.Delete(k)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -246,6 +255,42 @@ func (s *BoltStore) RemoveChannel(user *storage.User, server, channel string) er
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BoltStore) GetOpenDMs(user *storage.User) ([]storage.Tab, error) {
|
||||
var openDMs []storage.Tab
|
||||
|
||||
s.db.View(func(tx *bolt.Tx) error {
|
||||
c := tx.Bucket(bucketOpenDMs).Cursor()
|
||||
|
||||
for k, _ := c.Seek(user.IDBytes); bytes.HasPrefix(k, user.IDBytes); k, _ = c.Next() {
|
||||
tab := bytes.Split(k[8:], []byte{0})
|
||||
openDMs = append(openDMs, storage.Tab{
|
||||
Server: string(tab[0]),
|
||||
Name: string(tab[1]),
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return openDMs, nil
|
||||
}
|
||||
|
||||
func (s *BoltStore) AddOpenDM(user *storage.User, server, nick string) error {
|
||||
return s.db.Batch(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(bucketOpenDMs)
|
||||
|
||||
return b.Put(channelID(user, server, nick), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BoltStore) RemoveOpenDM(user *storage.User, server, nick string) error {
|
||||
return s.db.Batch(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(bucketOpenDMs)
|
||||
|
||||
return b.Delete(channelID(user, server, nick))
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BoltStore) LogMessage(message *storage.Message) error {
|
||||
return s.db.Batch(func(tx *bolt.Tx) error {
|
||||
b, err := tx.Bucket(bucketMessages).CreateBucketIfNotExists([]byte(message.Server + ":" + message.To))
|
||||
|
@ -38,6 +38,10 @@ type Store interface {
|
||||
GetChannels(user *User) ([]*Channel, error)
|
||||
AddChannel(user *User, channel *Channel) error
|
||||
RemoveChannel(user *User, server, channel string) error
|
||||
|
||||
GetOpenDMs(user *User) ([]Tab, error)
|
||||
AddOpenDM(user *User, server, nick string) error
|
||||
RemoveOpenDM(user *User, server, nick string) error
|
||||
}
|
||||
|
||||
type SessionStore interface {
|
||||
|
@ -190,6 +190,23 @@ func (u *User) RemoveChannel(server, channel string) error {
|
||||
return u.store.RemoveChannel(u, server, channel)
|
||||
}
|
||||
|
||||
type Tab struct {
|
||||
Server string
|
||||
Name string
|
||||
}
|
||||
|
||||
func (u *User) GetOpenDMs() ([]Tab, error) {
|
||||
return u.store.GetOpenDMs(u)
|
||||
}
|
||||
|
||||
func (u *User) AddOpenDM(server, nick string) error {
|
||||
return u.store.AddOpenDM(u, server, nick)
|
||||
}
|
||||
|
||||
func (u *User) RemoveOpenDM(server, nick string) error {
|
||||
return u.store.RemoveOpenDM(u, server, nick)
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
ID string `json:"-" bleve:"-"`
|
||||
Server string `json:"-" bleve:"server"`
|
||||
|
@ -80,6 +80,16 @@ func TestUser(t *testing.T) {
|
||||
channels, err = user.GetChannels()
|
||||
assert.Len(t, channels, 0)
|
||||
|
||||
user.AddOpenDM(srv.Host, "cake")
|
||||
openDMs, err := user.GetOpenDMs()
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, openDMs, 1)
|
||||
err = user.RemoveOpenDM(srv.Host, "cake")
|
||||
assert.Nil(t, err)
|
||||
openDMs, err = user.GetOpenDMs()
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, openDMs, 0)
|
||||
|
||||
settings := user.GetClientSettings()
|
||||
assert.NotNil(t, settings)
|
||||
assert.Equal(t, storage.DefaultClientSettings(), settings)
|
||||
|
Loading…
Reference in New Issue
Block a user