diff --git a/base/aaa/role.go b/base/aaa/role.go index cd93d8b1..fffd28f7 100644 --- a/base/aaa/role.go +++ b/base/aaa/role.go @@ -63,6 +63,7 @@ const ( ) const ( AUTH = "auth" + ACCESS = "access" PUBLIC = "public" PRIVATE = "private" CONFIRM = "confirm" diff --git a/base/web/dream.go b/base/web/dream.go index ab1d9528..69e2cc33 100644 --- a/base/web/dream.go +++ b/base/web/dream.go @@ -25,10 +25,7 @@ import ( func _dream_list(m *ice.Message, simple bool) *ice.Message { list := m.CmdMap(SPACE, mdb.NAME) mdb.HashSelects(m.Spawn()).Table(func(value ice.Maps, index int, head []string) { - if value["access"] == "private" { - // return - } - if value["access"] == "private" && !aaa.IsTechOrRoot(m) { + if value[aaa.ACCESS] == aaa.PRIVATE && (m.Option(ice.FROM_SPACE) != "" || !aaa.IsTechOrRoot(m)) { return } m.Push("", value, kit.Slice(head, 0, -1)) @@ -294,6 +291,7 @@ func init() { m.OptionDefault(mdb.ICONS, nfs.USR_ICONS_CONTEXTS) if mdb.HashCreate(m); ice.Info.Important == true { _dream_start(m, m.Option(mdb.NAME)) + StreamPushRefreshConfirm(m, m.Trans("refresh for new space ", "刷新列表查看新空间 ")+m.Option(mdb.NAME)) } }}, DOWNLOAD: {Name: "download path link", Hand: func(m *ice.Message, arg ...string) { @@ -427,7 +425,9 @@ func init() { } }}, "settings": {Name: "settings restart=manual,always access=public,private", Help: "设置", Hand: func(m *ice.Message, arg ...string) { - mdb.HashModify(m, m.OptionSimple(mdb.NAME, "restart", "access")) + kit.If(m.Option(cli.RESTART) == "manual", func() { m.Option(cli.RESTART, "") }) + kit.If(m.Option(aaa.ACCESS) == aaa.PUBLIC, func() { m.Option(aaa.ACCESS, "") }) + mdb.HashModify(m, m.OptionSimple(mdb.NAME, cli.RESTART, aaa.ACCESS)) }}, STATS_TABLES: {Hand: func(m *ice.Message, arg ...string) { if msg := _dream_list(m.Spawn(), true); msg.Length() > 0 { diff --git a/base/web/html/html.go b/base/web/html/html.go index 3bc54f07..fee9e9f6 100644 --- a/base/web/html/html.go +++ b/base/web/html/html.go @@ -77,6 +77,7 @@ const ( LAYOUT = "layout" RESIZE = "resize" REFRESH = "refresh" + CONFIRM = "confirm" FILTER = "filter" DANGER = "danger" diff --git a/base/web/matrix.go b/base/web/matrix.go index 5e851dc1..860a9d1e 100644 --- a/base/web/matrix.go +++ b/base/web/matrix.go @@ -131,6 +131,7 @@ func init() { mdb.TYPE, aaa.TECH, mdb.ICONS, nfs.USR_ICONS_ICEBERGS, TARGET, kit.Keys(ice.OPS, m.Option(DOMAIN), m.Option(mdb.NAME)), ) + StreamPushRefreshConfirm(m, m.Trans("refresh for new space ", "刷新列表查看新空间 ")+kit.Keys(m.Option(DOMAIN), m.Option(mdb.NAME))) }}, }, ctx.ConfAction(mdb.FIELD, "time,domain,status,type,name,text,icons,repos,binary,module,version", ctx.TOOLS, kit.Simple(SPIDE, STATUS, VERSION))), Hand: func(m *ice.Message, arg ...string) { if kit.HasPrefixList(arg, ctx.ACTION) { diff --git a/base/web/space.go b/base/web/space.go index e911cad8..e751b61b 100644 --- a/base/web/space.go +++ b/base/web/space.go @@ -92,6 +92,7 @@ func _space_fork(m *ice.Message) { gdb.Event(m, SPACE_LOGIN, args) defer gdb.Event(m, SPACE_LOGIN_CLOSE, args) case PORTAL: + defer gdb.EventDeferEvent(m, PORTAL_OPEN, args)(PORTAL_CLOSE, args) m.Go(func() { m.Cmd(SPACE, name, cli.PWD, name) }) case WORKER: defer gdb.EventDeferEvent(m, DREAM_OPEN, args)(DREAM_CLOSE, args) @@ -267,6 +268,8 @@ const ( SPACE_GRANT = "space.grant" SPACE_OPEN = "space.open" SPACE_CLOSE = "space.close" + PORTAL_OPEN = "portal.open" + PORTAL_CLOSE = "portal.close" ) const SPACE = "space" diff --git a/base/web/stream.go b/base/web/stream.go index cc74fa50..4e2354b1 100644 --- a/base/web/stream.go +++ b/base/web/stream.go @@ -1,39 +1,69 @@ package web import ( + "strings" + ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/ctx" + "shylinux.com/x/icebergs/base/gdb" "shylinux.com/x/icebergs/base/mdb" + "shylinux.com/x/icebergs/base/web/html" kit "shylinux.com/x/toolkits" ) +func _stream_subkey(m *ice.Message, arg ...string) *ice.Message { + kit.If(len(arg) == 0, func() { arg = append(arg, kit.Hashs(kit.Fields(m.Option(ice.MSG_SPACE), m.Option(ice.MSG_INDEX)))) }) + return m.Options(mdb.SUBKEY, kit.Keys(mdb.HASH, arg[0]), ice.MSG_FIELDS, mdb.Config(m, mdb.FIELDS)) +} + const STREAM = "stream" func init() { Index.MergeCommands(ice.Commands{ - STREAM: {Name: "stream hash daemon auto", Help: "在线", Actions: ice.MergeActions(ice.Actions{ + STREAM: {Name: "stream hash daemon auto", Help: "推送流", Actions: ice.MergeActions(ice.Actions{ ONLINE: {Hand: func(m *ice.Message, arg ...string) { - mdb.HashCreate(m, SPACE, m.Option(ice.MSG_SPACE), ctx.INDEX, m.Option(ice.MSG_INDEX), - mdb.SHORT, cli.DAEMON, mdb.FIELD, mdb.Config(m, mdb.FIELDS)) - m.Option(mdb.SUBKEY, kit.Keys(mdb.HASH, kit.Hashs(kit.Fields(m.Option(ice.MSG_SPACE), m.Option(ice.MSG_INDEX))))) - mdb.HashCreate(m, ParseUA(m)) - mdb.HashSelect(m.Options(ice.MSG_FIELDS, mdb.Config(m, mdb.FIELDS))) + mdb.HashCreate(m, SPACE, m.Option(ice.MSG_SPACE), ctx.INDEX, m.Option(ice.MSG_INDEX), mdb.SHORT, cli.DAEMON, mdb.FIELD, mdb.Config(m, mdb.FIELDS)) + mdb.HashCreate(_stream_subkey(m), ParseUA(m)) + mdb.HashSelect(m) }}, "push": {Hand: func(m *ice.Message, arg ...string) { - m.Option(mdb.SUBKEY, kit.Keys(mdb.HASH, kit.Hashs(kit.Fields(m.Option(ice.MSG_SPACE), m.Option(ice.MSG_INDEX))))) - mdb.HashSelect(m).Table(func(value ice.Maps) { m.Cmd(SPACE, value[cli.DAEMON], arg) }) + mdb.HashSelect(_stream_subkey(m)).Table(func(value ice.Maps) { + if value[cli.DAEMON] != m.Option(ice.MSG_DAEMON) { + m.Options(mdb.SUBKEY, "").Cmd(SPACE, value[cli.DAEMON], arg) + } + }) }}, - }, mdb.HashAction( + PORTAL_CLOSE: {Hand: func(m *ice.Message, arg ...string) { + mdb.HashSelect(m).Table(func(value ice.Maps) { + mdb.HashSelect(_stream_subkey(m, value[mdb.HASH]).Spawn()).Table(func(value ice.Maps) { + if strings.HasPrefix(value[cli.DAEMON], m.Option(mdb.NAME)) { + mdb.HashRemove(m, mdb.HASH, kit.Hashs(value[cli.DAEMON])) + } + }) + }) + }}, + }, gdb.EventsAction(PORTAL_CLOSE), mdb.ClearOnExitHashAction(), mdb.HashAction( mdb.SHORT, "space,index", mdb.FIELD, "time,hash,space,index", mdb.FIELDS, "time,daemon,userrole,username,usernick,avatar,icons,agent,system,ip,ua", )), Hand: func(m *ice.Message, arg ...string) { if len(arg) == 0 { mdb.HashSelect(m) } else { - m.Option(mdb.SUBKEY, kit.Keys(mdb.HASH, arg[0])) - mdb.HashSelect(m.Options(ice.MSG_FIELDS, mdb.Config(m, mdb.FIELDS)), arg[1:]...) + mdb.HashSelect(_stream_subkey(m, arg[0]), arg[1:]...) } }}, }) } +func StreamPush(m *ice.Message, arg ...string) { + if ice.Info.NodeType == WORKER { + m.Option(ice.MSG_SPACE, m.Option(ice.MSG_USERPOD)) + } else { + m.Option(ice.MSG_SPACE, "") + } + m.Option(ice.MSG_INDEX, m.ShortKey()) + AdminCmd(m, STREAM, "push", arg) +} +func StreamPushRefreshConfirm(m *ice.Message, arg ...string) { + StreamPush(m.Spawn(ice.Maps{"space.noecho": "true"}), kit.Simple(html.REFRESH, html.CONFIRM, arg)...) +} diff --git a/core/chat/message.go b/core/chat/message.go index 85a05fa4..2f09eb37 100644 --- a/core/chat/message.go +++ b/core/chat/message.go @@ -33,20 +33,20 @@ func init() { mdb.ZoneInsert(m, append(arg, "direct", tcp.SEND, aaa.USERNAME, m.Option(ice.MSG_USERNAME), aaa.USERNICK, m.Option(ice.MSG_USERNICK), aaa.AVATAR, m.Option(ice.MSG_AVATAR))) kit.If(mdb.HashSelectField(m, arg[0], web.TARGET), func(p string) { m.Cmd(web.SPACE, p, MESSAGE, tcp.RECV, arg[1:]) }) mdb.HashSelectUpdate(m, arg[0], func(value ice.Map) { kit.Value(value, mdb.TIME, m.Time()) }) + web.StreamPushRefreshConfirm(m, m.Trans("refresh for new message ", "刷新列表查看新消息 ")) }}, tcp.RECV: {Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) { mdb.ZoneInsert(m, kit.Simple(mdb.ZONE, m.Option(ice.FROM_SPACE), arg, "direct", tcp.RECV, aaa.USERNAME, m.Option(ice.MSG_USERNAME), aaa.USERNICK, m.Option(ice.MSG_USERNICK), aaa.AVATAR, m.Option(ice.MSG_AVATAR))) mdb.HashSelectUpdate(m, m.Option(ice.FROM_SPACE), func(value ice.Map) { kit.Value(value, web.TARGET, m.Option(ice.FROM_SPACE)) }) mdb.HashSelectUpdate(m, m.Option(ice.FROM_SPACE), func(value ice.Map) { kit.Value(value, mdb.TIME, m.Time()) }) + web.StreamPushRefreshConfirm(m, m.Trans("refresh for new message ", "刷新列表查看新消息 ")) }}, web.DREAM_CREATE: {Hand: func(m *ice.Message, arg ...string) { if ice.Info.Important { messageInsert(m, web.DREAM, mdb.TYPE, "plug", ctx.INDEX, IFRAME, ctx.ARGS, web.S(m.Option(mdb.NAME))) } }}, - web.OPEN: {Hand: func(m *ice.Message, arg ...string) { - m.ProcessOpen(m.MergePod(m.Option(web.TARGET))) - }}, + web.OPEN: {Hand: func(m *ice.Message, arg ...string) { m.ProcessOpen(m.MergePod(m.Option(web.TARGET))) }}, ctx.COMMAND: {Hand: func(m *ice.Message, arg ...string) { if m.Option("direct") == "recv" { m.Cmdy(web.Space(m, m.Option(web.TARGET)), ctx.COMMAND, arg[0]).ProcessField(ctx.ACTION, ctx.RUN, m.Option(web.TARGET), arg[0]) @@ -54,9 +54,7 @@ func init() { m.Cmdy(ctx.COMMAND, arg[0]).ProcessField(ctx.ACTION, ctx.RUN, "", arg[0]) } }}, - ctx.RUN: {Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(web.Space(m, arg[0]), arg[1], arg[2:]) - }}, + ctx.RUN: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(web.Space(m, arg[0]), arg[1], arg[2:]) }}, }, web.DreamAction(), web.DreamTablesAction(), mdb.ZoneAction( mdb.SHORT, mdb.ZONE, mdb.FIELD, "time,hash,type,zone,icons,title,count,target", mdb.FIELDS, "time,id,type,name,text,space,index,args,style,display,username,usernick,avatar,direct", diff --git a/core/chat/message.js b/core/chat/message.js index 6fb1ad4d..8d7d30da 100644 --- a/core/chat/message.js +++ b/core/chat/message.js @@ -4,7 +4,7 @@ Volcanos(chat.ONIMPORT, { can.ui = can.onappend.layout(can), can.onimport._project(can, msg) can.onimport._online(can) }, - _project: function(can, msg) { var select, current = can.db.hash[0]||ice.DEV + _project: function(can, msg) { var select, current = can.db.hash[0]||can.sup.db.current||ice.DEV can.page.insertBefore(can, [{view: wiki.TITLE, list: [ {icon: "bi bi-three-dots", onclick: function() { can._legend.onclick(event) }}, {text: "message"||can.ConfIndex(), onclick: function(event) { can._legend.onclick(event) }}, @@ -17,6 +17,7 @@ Volcanos(chat.ONIMPORT, { {view: wiki.CONTENT, list: [{text: value.target||"[未知消息]"}]}, ]}, ], onclick: function(event) { can.isCmdMode() && can.misc.SearchHash(can, value.zone), can.onimport._switch(can, false) + can.sup.db.current = value.zone can.db.zone = value, can.db.hash = value.hash, can.onmotion.select(can, can.ui.project, html.DIV_ITEM, _target) if (can.onmotion.cache(can, function(save, load) { can.ui.message && save({title: can.ui.title, message: can.ui.message, scroll: can.ui.message.scrollTop}) @@ -89,6 +90,9 @@ Volcanos(chat.ONIMPORT, { can.ui.title && can.page.style(can, can.ui.message, html.HEIGHT, can.ui.content.offsetHeight-can.ui.title.offsetHeight) }, }, [""]) +Volcanos(chat.ONDAEMON, { + refresh: function(can, msg, sub, arg) { can.base.isFunc(sub.Update) && sub.Update(), can.user.toast(can, "new message") }, +}) Volcanos(chat.ONEXPORT, { plugHeight: function(can, value) { var height = can.base.Min(can.ui.content.offsetHeight-240, 240) return can.base.Max(html.STORY_HEIGHT, height, height/(can.base.isIn(value.index, html.IFRAME)? 1: 2))