package web import ( "net/url" "strings" "time" ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/log" "shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/tcp" kit "shylinux.com/x/toolkits" "shylinux.com/x/toolkits/file" ) type Message interface { Option(key string, arg ...ice.Any) string PrefixKey() string } func UserWeb(m Message) *url.URL { return kit.ParseURL(m.Option(ice.MSG_USERWEB)) } func UserHost(m *ice.Message) string { if p := m.Option(ice.MSG_USERHOST); p != "" { return p } else if u := UserWeb(m); strings.Contains(u.Host, tcp.LOCALHOST) { return m.Option(ice.MSG_USERHOST, tcp.PublishLocalhost(m, u.Scheme+"://"+u.Host)) } else { return m.Option(ice.MSG_USERHOST, u.Scheme+"://"+u.Host) } } func AgentIs(m Message, arg ...string) bool { for _, k := range arg { if strings.HasPrefix(strings.ToLower(m.Option(ice.MSG_USERUA)), k) { return true } } return false } func MergeURL2(m *ice.Message, url string, arg ...ice.Any) string { kit.If(m.Option(log.DEBUG) == ice.TRUE, func() { arg = append(arg, log.DEBUG, ice.TRUE) }) kit.If(m.Option(ice.MSG_USERWEB) == "", func() { m.Option(ice.MSG_USERWEB, Domain(ice.Pulse.Cmdv(tcp.HOST, aaa.IP), ice.Pulse.Cmdv(SERVE, tcp.PORT))) }) return kit.MergeURL2(m.Option(ice.MSG_USERWEB), url, arg...) } func MergeLink(m *ice.Message, url string, arg ...ice.Any) string { kit.If(m.Option(log.DEBUG) == ice.TRUE, func() { arg = append(arg, log.DEBUG, ice.TRUE) }) return kit.MergeURL(strings.Split(MergeURL2(m, url), QS)[0], arg...) } func ParseLink(m *ice.Message, url string) ice.Maps { list := ice.Maps{} u := kit.ParseURL(url) switch arg := strings.Split(strings.TrimPrefix(u.Path, nfs.PS), nfs.PS); arg[0] { case CHAT: kit.For(arg[1:], func(k, v string) { list[k] = v }) case SHARE: list[arg[0]] = arg[1] } kit.For(u.Query(), func(k string, v []string) { list[k] = v[0] }) return list } func ProcessPodCmd(m *ice.Message, pod, cmd string, arg ...ice.Any) { m.ProcessOpen(m.MergePodCmd(pod, cmd, arg...)) } func ProcessIframe(m *ice.Message, name, link string, arg ...string) { ctx.ProcessField(m, CHAT_IFRAME, func() []string { return []string{m.Cmdx(CHAT_IFRAME, mdb.CREATE, mdb.TYPE, LINK, mdb.NAME, name, LINK, link)} }, arg...) } func PushPodCmd(m *ice.Message, cmd string, arg ...string) *ice.Message { list := []string{} m.Cmds(SPACE, func(value ice.Maps) { kit.If(kit.IsIn(value[mdb.TYPE], WORKER), func() { list = append(list, value[mdb.NAME]) }) }) if len(list) == 0 { return m } kit.If(m.Length() > 0 && len(m.Appendv(SPACE)) == 0, func() { m.Table(func(value ice.Maps) { m.Push(SPACE, "") }) }) GoToast(m, "", func(toast func(string, int, int)) []string { kit.For(list, func(index int, space string) { toast(space, index, len(list)) m.Cmd(SPACE, space, kit.Dict(ice.MSG_USERPOD, space), kit.Select(m.PrefixKey(), cmd), arg).Table(func(index int, val ice.Maps, head []string) { kit.If(!kit.IsIn(SPACE, head...), func() { head = append(head, SPACE) }) val[SPACE] = kit.Keys(space, val[SPACE]) m.Push("", val, head) }) }) return nil }) return m } func PushImages(m *ice.Message, name string) { if kit.ExtIsImage(name) { m.PushImages(IMAGE, name) } else if kit.ExtIsVideo(name) { m.PushVideos(VIDEO, name) } } func PushNotice(m *ice.Message, arg ...ice.Any) { opts := ice.Map{ice.MSG_OPTION: []string{}, ice.MSG_OPTS: []string{}} kit.For([]string{ctx.DISPLAY, ctx.STYLE, "delay", ice.LOG_DEBUG, ice.LOG_TRACEID}, func(key string) { opts[ice.MSG_OPTION] = kit.Simple(opts[ice.MSG_OPTION], key) opts[key] = m.Option(key) }) if m.Option(ice.MSG_DAEMON) == "" { return } else if m.Option(ice.MSG_USERPOD) == "" { m.Cmd(SPACE, m.Option(ice.MSG_DAEMON), arg, opts) } else { m.Cmd(SPACE, kit.Keys(m.Option("__target"), m.Option(ice.MSG_DAEMON)), arg, opts) } } func PushNoticeToast(m *ice.Message, arg ...ice.Any) { PushNotice(m, kit.List("toast", arg)...) } func PushNoticeGrow(m *ice.Message, arg ...ice.Any) { PushNotice(m, kit.List("grow", arg)...) } func PushNoticeRich(m *ice.Message, arg ...ice.Any) { PushNotice(m, kit.List("rich", arg)...) } func PushStream(m *ice.Message) *ice.Message { m.Options(cli.CMD_OUTPUT, file.NewWriteCloser(func(buf []byte) { PushNoticeGrow(m, string(buf)) }, nil)).ProcessHold(toastContent(m, ice.SUCCESS)) return m } func init() { ice.Info.PushStream = PushStream } func init() { ice.Info.PushNotice = PushNotice } func Toast(m *ice.Message, text string, arg ...ice.Any) *ice.Message { // [title [duration [progress]]] if len(arg) > 1 { switch val := arg[1].(type) { case string: if value, err := time.ParseDuration(val); err == nil { arg[1] = int(value / time.Millisecond) } } } kit.If(len(arg) == 0, func() { arg = append(arg, m.PrefixKey()) }) kit.If(len(arg) > 0, func() { arg[0] = kit.Select(m.PrefixKey(), arg[0]) }) PushNoticeToast(m, text, arg) return m } var Icons = map[string]string{ice.PROCESS: "🕑", ice.FAILURE: "❌", ice.SUCCESS: "✅"} func toastContent(m *ice.Message, state string, arg ...ice.Any) string { return kit.JoinWord(kit.Simple(Icons[state], m.ActionKey(), state, arg)...) } func ToastSuccess(m *ice.Message, arg ...ice.Any) { Toast(m, toastContent(m, ice.SUCCESS, arg...), "", "1s") } func ToastFailure(m *ice.Message, arg ...ice.Any) { Toast(m, toastContent(m, ice.FAILURE, arg...), "", m.OptionDefault(ice.TOAST_DURATION, "3s")).Sleep(m.OptionDefault(ice.TOAST_DURATION, "3s")) } func ToastProcess(m *ice.Message, arg ...ice.Any) func() { Toast(m, toastContent(m, ice.PROCESS, arg...), "", "30s") return func() { Toast(m, toastContent(m, ice.SUCCESS, arg...), "", "1s") } } func GoToast(m *ice.Message, title string, cb func(toast func(name string, count, total int)) []string) *ice.Message { _total := 0 icon := Icons[ice.PROCESS] toast := func(name string, count, total int) { kit.If(total == 0, func() { total = 1 }) Toast(m, kit.Format("%s %s %s/%s", icon, kit.JoinWord(m.ActionKey(), name), strings.TrimSuffix(kit.FmtSize(int64(count)), "B"), strings.TrimSuffix(kit.FmtSize(int64(total)), "B")), "", m.OptionDefault(ice.TOAST_DURATION, "30s"), count*100/total) _total = total } if list := cb(toast); len(list) > 0 { icon = Icons[ice.FAILURE] m.Option(ice.TOAST_DURATION, "10s") toast(kit.JoinWord(list...), len(list), _total) } else { icon = Icons[ice.SUCCESS] m.Option(ice.TOAST_DURATION, "1s") toast(ice.SUCCESS, _total, _total) } m.Sleep(m.Option(ice.TOAST_DURATION)) return m }