1
0
mirror of https://shylinux.com/x/volcanos synced 2025-04-25 16:58:06 +08:00

opt chrome

This commit is contained in:
bergyu 2021-12-29 17:22:59 +08:00
parent 39e710dbc4
commit e6aa35715d
12 changed files with 130 additions and 164 deletions

View File

@ -3,7 +3,9 @@
"name": "volcanos", "version": "0.0.1", "name": "volcanos", "version": "0.0.1",
"background": {"page": "/publish/chrome/chrome.html"}, "background": {"page": "/publish/chrome/chrome.html"},
"browser_action": {"default_popup": "/publish/chrome/popup.html"}, "browser_action": {"default_popup": "/publish/chrome/popup.html"},
"content_scripts": [{"matches": ["<all_urls>"], "css": ["/publish/chrome/contexts.css"], "content_scripts": [{"matches": ["<all_urls>"], "css": [
"/page/cache.css", "/publish/chrome/contexts.css"
],
"js": ["/proto.js", "/publish/chrome/contexts.js", "/page/cache.js", "/frame.js"]} "js": ["/proto.js", "/publish/chrome/contexts.js", "/page/cache.js", "/frame.js"]}
], ],
"permissions": [ "permissions": [

View File

@ -195,6 +195,8 @@ table.content th:hover {
table.content td { table.content td {
padding:2px 6px; padding:2px 6px;
overflow:auto; overflow:auto;
max-width:800px;
white-space:break-spaces;
} }
table.content td.done { table.content td.done {
background-color:green; background-color:green;

View File

@ -44,6 +44,7 @@ Volcanos({name: "chat", panels: [
}}, }},
{name: "cached", help: "爬虫缓存", index: "web.code.chrome.cache", args: []}, {name: "cached", help: "爬虫缓存", index: "web.code.chrome.cache", args: []},
{name: "spided", help: "网页爬虫", index: "web.code.chrome.spide", args: location && location.protocol && location.protocol=="chrome-extension:"? ["1", "", "spide"]: ["1"]}, {name: "spided", help: "网页爬虫", index: "web.code.chrome.spide", args: location && location.protocol && location.protocol=="chrome-extension:"? ["1", "", "spide"]: ["1"]},
{name: "modify", help: "编辑页面", index: "web.code.chrome.modify", args: []},
]}, ]},
}}, }},
project: {name: "研发群", storm: { project: {name: "研发群", storm: {

View File

@ -13,9 +13,6 @@ fieldset.panel.cmd>div.output>fieldset.plugin>div.legend {
background-color:darkcyan; background-color:darkcyan;
cursor:pointer; cursor:pointer;
} }
fieldset.plugin>legend {
display:none;
}
body.white fieldset.panel.cmd>div.output>fieldset.plugin>div.legend { body.white fieldset.panel.cmd>div.output>fieldset.plugin>div.legend {
background-color:honeydew; background-color:honeydew;
} }

View File

@ -67,15 +67,18 @@ Volcanos("onengine", {help: "解析引擎", list: [], _engine: function(event, c
}, },
}) })
Volcanos("onaction", {help: "控件交互", list: [], _init: function(can, msg, list, cb, target) { Volcanos("onaction", {help: "控件交互", list: [], _init: function(can, msg, list, cb, target) {
can.onengine.plugin(can, "info", shy("信息", {}, ["text", "list", "back"], function(msg, cmds) {
msg.Echo(JSON.stringify(can))
}))
can.onengine.plugin(can, "log", shy("日志", {}, ["text", "list", "back"], function(msg, cmds) { can.onengine.plugin(can, "log", shy("日志", {}, ["text", "list", "back"], function(msg, cmds) {
console.log(cmds[0]) console.log(cmds[0])
msg.Option(ice.MSG_DISPLAY, "/plugin/story/pie.js") msg.Option(ice.MSG_DISPLAY, "/plugin/story/pie.js")
})) }))
can.onengine.plugin(can, "pie", shy("比例图", {}, ["list", "back"], function(msg, cmds) { can.onengine.plugin(can, "pie", shy("比例图", {}, ["list", "back"], function(msg, cmds) {
msg.Option(ice.MSG_DISPLAY, "/plugin/story/pie.js")
msg.Push("value", 200) msg.Push("value", 200)
msg.Push("value", 300) msg.Push("value", 300)
msg.Push("value", 400) msg.Push("value", 400)
msg.Option(ice.MSG_DISPLAY, "/plugin/story/pie.js")
})) }))
can.base.isFunc(cb) && cb() can.base.isFunc(cb) && cb()
}, },

View File

@ -189,6 +189,7 @@ var html = {
WSS: "wss", SVG: "svg", WSS: "wss", SVG: "svg",
MAX_HEIGHT: "max-height", MAX_WIDTH: "max-width", MAX_HEIGHT: "max-height", MAX_WIDTH: "max-width",
MAX_HEIGHT: "max-height", MAX_HEIGHT: "max-height",
CHROME: "chrome",
} }
var lang = { var lang = {
STRING: "string", NUMBER: "number", STRING: "string", NUMBER: "number",

View File

@ -1,7 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head><meta charset="utf-8"></head> <head><meta charset="utf-8"></head>
<body><script src="/proto.js"></script> <body>
<script src="/proto.js"></script>
<script src="/publish/chrome/chrome.js"></script> <script src="/publish/chrome/chrome.js"></script>
</body> </body>
</html> </html>

View File

@ -1,69 +1,63 @@
Volcanos({ Volcanos({
pwd: function(can, msg, arg) {
msg.Push("hi", "hello")
msg.Echo("hello")
},
chrome: function(can, msg, arg, cb) { chrome: function(can, msg, arg, cb) {
if (arg.length == 0) { // 窗口列表 if (arg.length == 0 || arg[0] == "") { // 窗口列表
chrome.windows.getAll(function(wins) { chrome.windows.getAll(function(wins) {
can.core.List(wins, function(win) { win.wid = win.id can.core.List(wins, function(win) { win.wid = win.id
msg.Push(win, ["wid", "state", "left", "top", "width", "height"]) msg.Push(win, ["wid", "state", html.LEFT, html.TOP, html.WIDTH, html.HEIGHT])
}), can.base.isFunc(cb) && cb(msg)
}) })
can.base.isFunc(cb) && cb(msg) } else if (arg.length == 1 || arg[1] == "") { // 标签列表
})
} else if (arg.length == 1) { // 标签列表
chrome.tabs.getAllInWindow(parseInt(arg[0]), function(tabs) { chrome.tabs.getAllInWindow(parseInt(arg[0]), function(tabs) {
can.core.List(tabs, function(tab) { tab.tid = tab.id can.core.List(tabs, function(tab) { tab.tid = tab.id
msg.Push(tab, ["tid", "active", "width", "height", "index", "title", "url"]) msg.Push(tab, ["tid", "active", html.WIDTH, html.HEIGHT, "index", "title", "url"])
}), can.base.isFunc(cb) && cb(msg)
}) })
can.base.isFunc(cb) && cb(msg) } else if (arg[1] == "current") { // 当前标签
})
} else if (arg[1] == "") { // 当前标签
chrome.tabs.query({currentWindow: true, active: true}, function(tabs) { arg[1] = tabs[0].id chrome.tabs.query({currentWindow: true, active: true}, function(tabs) { arg[1] = tabs[0].id
chrome.tabs.sendMessage(parseInt(arg[1]), msg, function(res) { chrome.tabs.sendMessage(parseInt(arg[1]), msg, function(res) {
can.base.isFunc(cb) && cb(msg.Copy(res)) can.base.isFunc(cb) && cb(msg.Copy(res))
}) })
}) })
} else { } else { // 下发命令
chrome.tabs.sendMessage(parseInt(arg[1]), msg, function(res) { chrome.tabs.sendMessage(parseInt(arg[1]), msg, function(res) {
can.base.isFunc(cb) && cb(msg.Copy(res)) can.base.isFunc(cb) && cb(msg.Copy(res))
}) })
} }
}, },
}, function(can) { _daemon: function(can) {
can.run = function(event, cmds, cb) { var msg = can.request(event) can.misc.WSS(can, {type: html.CHROME, name: html.CHROME}, function(event, msg, cmd, arg) {
can.misc.Run(event, can, {names: "http://localhost:9020/code/chrome/"+cmds[0]}, cmds.slice(1), cb) if (msg.Option(ice.MSG_TARGET)) { msg.detail = ["", "", ""].concat(msg.detail)
}, chrome.tabs.sendMessage(parseInt(msg.Option(ice.MSG_TARGET)), msg, function(res) {
chrome.history.onVisited.addListener(function(item) {
can.run({}, ["sync", kit.MDB_TYPE, "link", kit.MDB_NAME, item.title, kit.MDB_TEXT, item.url, "tid", item.id])
})
can.user.toast = function(can, message, title) { chrome.notifications.create(null, {
message: message, title: title||can._name, iconUrl: "/favicon.ico", type: "basic",
})},
can.misc.WSS(can, {type: "chrome", name: "chrome"}, function(event, msg, cmd, arg) {
if (msg.Option("_target")) { msg.detail = ["", "", ""].concat(msg.detail)
chrome.tabs.sendMessage(parseInt(msg.Option("_target")), msg, function(res) {
msg.Copy(res), msg.Reply() msg.Copy(res), msg.Reply()
}) })
return return
} }
can.core.CallFunc([can, cmd], {can: can, msg: msg, arg: arg, cb: function() { msg.Reply() }}) can.core.CallFunc([can, cmd], {can: can, msg: msg, arg: arg, cb: function() { msg.Reply() }})
}) })
chrome.runtime.onMessage.addListener(function(req, sender, cb) { chrome.runtime.onMessage.addListener(function(req, sender, cb) {
var msg = can.request({}, {tid: sender.tab.id, url: sender.url}) var msg = can.request({}, {tid: sender.tab.id, url: sender.url}); msg.__daemon = can.core.Keys(html.CHROME, sender.tab.id)
msg.__daemon = "chrome."+sender.tab.id
can.core.List(req.option, function(key) { msg.Option(key, req[key][0]) }) can.core.List(req.option, function(key) { msg.Option(key, req[key][0]) })
can.run(msg._event, req.detail||[], cb) can.run(msg._event, req.detail||[], cb)
return true return true
}) })
chrome.history.onVisited.addListener(function(item) {
chrome.contextMenus.create({title: "field", onclick: function(event) { can.run({}, ["sync", kit.MDB_TYPE, "link", kit.MDB_NAME, item.title, kit.MDB_TEXT, item.url, "tid", item.id])
})
},
_motion: function(can) {
can.user.toast = function(can, message, title) { chrome.notifications.create(null, {
message: message, title: title||can._name, iconUrl: "/favicon.ico", type: "basic",
})},
chrome.contextMenus.create({title: "volcanos", onclick: function(event) {
chrome.tabs.query({currentWindow: true, active: true}, function(tabs) { chrome.tabs.query({currentWindow: true, active: true}, function(tabs) {
var msg = can.request(event); msg.detail = ["chrome", "", "", "order"] var msg = can.request(event); msg.detail = [html.CHROME, "", "", "order"]
chrome.tabs.sendMessage(tabs[0].id, msg) chrome.tabs.sendMessage(tabs[0].id, msg)
}) })
}}) }})
},
}, function(can) {
can.run = function(event, cmds, cb) { var msg = can.request(event)
can.misc.Run(event, can, {names: "http://localhost:9020/code/chrome/"+cmds[0]}, cmds.slice(1), cb)
}, can._daemon(can), can._motion(can)
}) })

View File

@ -71,7 +71,9 @@ fieldset.contexts div.code {
overflow:auto; overflow:auto;
clear:both; clear:both;
} }
div.input.contexts input {
color:black;
}
table.content { table.content {
border:0; white-space:pre; border:0; white-space:pre;

View File

@ -1,20 +1,54 @@
setTimeout(function() { Volcanos({ setTimeout(function() { Volcanos({
pwd: function(can, msg, arg) { spide: function(can, msg, arg) { var has = {}
msg.Push("hi", "hello") can.page.Select(can, document.body, html.VIDEO, function(item) {
msg.Echo("hello") if (!item.src || has[item.src]) { return } has[item.src] = true
var p = can.page.Select(can, document.body, "p.title")[0]
var ls = item.src.split("?")
var ls = ls[0].split(ice.PT)
msg.Push(kit.MDB_TIME, can.base.Time())
msg.Push(kit.MDB_TYPE, html.VIDEO)
msg.Push(kit.MDB_NAME, (p && p.innerText || html.VIDEO)+ice.PT+ls[ls.length-1])
msg.Push(kit.MDB_TEXT, item.src)
msg.Push(kit.MDB_LINK, item.src)
})
can.page.Select(can, document.body, html.IMG, function(item) {
if (!item.src || has[item.src]) { return } has[item.src] = true
var ls = item.src.split("?")
var ls = ls[0].split(ice.PS)
msg.Push(kit.MDB_TIME, can.base.Time())
msg.Push(kit.MDB_TYPE, html.IMG)
if (item.src.indexOf("data:image") == 0) {
msg.Push(kit.MDB_NAME, item.src.slice(item.src.length-20))
} else {
msg.Push(kit.MDB_NAME, ls[ls.length-1]||"image.jpg")
}
msg.Push(kit.MDB_TEXT, item.src)
msg.Push(kit.MDB_LINK, item.src)
})
}, },
style: function(can, msg, arg) { change: function(can, msg, arg) {
can.core.List(arg[0].split(ice.FS), function(item) { if (arg.length > 1) {
can.page.Select(can, document.body, item, function(target) { can.page.Modify(can, arg[0], can.base.Obj(arg[1]))
can.page.Modify(can, target, can.base.Obj(arg[1])) }
if (arg.length > 0) {
can.page.Select(can, document.body, arg[0], function(item) {
msg.Push(kit.MDB_TEXT, item.outerHTML)
}) })
}
},
order: function(can, msg, arg) {
var ui = can.user.input(event, can, ["index", "args", "selection", "left", "top"], function(event, button, data, list, args) {
can.run(event, [chat.FIELD, mdb.INSERT, kit.MDB_ZONE, location.host].concat(args), function(res) {
can.user.toastSuccess(can)
}) })
}); can.page.Modify(can, ui._target, {style: {left: 200, top: 200}})
can.page.ClassList.add(can, ui._target, chat.CONTEXTS)
}, },
field: function(can, msg, arg) { field: function(can, msg, arg) {
can.onmotion.float.auto(can, document.body)
document.body.ondblclick = function(event) {
can.onengine.signal(can, "onselection")
}
can.onappend.plugin(can, {type: chat.CONTEXTS, index: arg[0], args: can.base.Obj(arg[1])}, function(sub, meta) { can.onappend.plugin(can, {type: chat.CONTEXTS, index: arg[0], args: can.base.Obj(arg[1])}, function(sub, meta) {
var pos = {left: msg.Option(chat.LEFT), top: msg.Option(chat.TOP), right: msg.Option(chat.RIGHT), bottom: msg.Option(chat.BOTTOM)} var pos = {left: msg.Option(chat.LEFT), top: msg.Option(chat.TOP), right: msg.Option(chat.RIGHT), bottom: msg.Option(chat.BOTTOM)}
can.page.Modify(can, sub._target, {style: pos}) can.page.Modify(can, sub._target, {style: pos})
@ -50,58 +84,34 @@ setTimeout(function() { Volcanos({
} }
}, document.body) }, document.body)
}, },
order: function(can, msg, arg) { style: function(can, msg, arg) {
var ui = can.user.input(event, can, ["index", "args", "selection", "left", "top"], function(event, button, data, list, args) { can.core.List(arg[0].split(ice.FS), function(item) {
can.run(event, [chat.FIELD, mdb.INSERT, kit.MDB_ZONE, location.host].concat(args), function(res) { can.page.Select(can, document.body, item, function(target) {
can.user.toastSuccess(can) can.page.Modify(can, target, can.base.Obj(arg[1]))
}) })
}); can.page.Modify(can, ui._target, {style: {left: 200, top: 200}})
can.page.ClassList.add(can, ui._target, chat.CONTEXTS)
},
spide: function(can, msg, arg) { var has = {}
can.page.Select(can, document.body, html.VIDEO, function(item) {
if (!item.src || has[item.src]) { return } has[item.src] = true
var p = can.page.Select(can, document.body, "p.title")[0]
var ls = item.src.split("?")
var ls = ls[0].split(ice.PT)
msg.Push(kit.MDB_TIME, can.base.Time())
msg.Push(kit.MDB_TYPE, html.VIDEO)
msg.Push(kit.MDB_NAME, (p && p.innerText || html.VIDEO)+ice.PT+ls[ls.length-1])
msg.Push(kit.MDB_TEXT, item.src)
msg.Push(kit.MDB_LINK, item.src)
})
can.page.Select(can, document.body, html.IMG, function(item) {
if (!item.src || has[item.src]) { return } has[item.src] = true
var ls = item.src.split("?")
var ls = ls[0].split(ice.PS)
msg.Push(kit.MDB_TIME, can.base.Time())
msg.Push(kit.MDB_TYPE, html.IMG)
if (item.src.indexOf("data:image") == 0) {
msg.Push(kit.MDB_NAME, item.src.slice(item.src.length-20))
} else {
msg.Push(kit.MDB_NAME, ls[ls.length-1]||"image.jpg")
}
msg.Push(kit.MDB_TEXT, item.src)
msg.Push(kit.MDB_LINK, item.src)
}) })
}, },
Option: function() { return [] }, Option: function() { return [] },
}, function(can) {
_daemon: function(can) {
chrome.extension.onMessage.addListener(function(req, sender, cb) { var msg = can.request(); msg.Copy(req); can.misc.Log(req.detail, msg) chrome.extension.onMessage.addListener(function(req, sender, cb) { var msg = can.request(); msg.Copy(req); can.misc.Log(req.detail, msg)
can.core.CallFunc([can, req.detail[3]||"spide"], {can: can, msg: msg, arg: req.detail.slice(4), cb: function() { can.core.CallFunc([can, req.detail[3]||"spide"], {can: can, msg: msg, arg: req.detail.slice(4), cb: function() {
delete(msg._event), delete(msg._can), cb(msg) delete(msg._event), delete(msg._can), cb(msg)
}}) }})
}) })
},
_motion: function(can) {
can.onmotion.float.auto(can, document.body)
document.body.ondblclick = function(event) { can.onengine.signal(can, "onselection") }
can.run = function(event, cmds, cb) { if (cmds[0] == "_search") { return }
var msg = can.request(event, {host: location.host}); msg.detail = can.misc.concat(["page"], cmds)
chrome.runtime.sendMessage(msg, function(res) { can.base.isFunc(cb) && cb(msg.Copy(res)) })
}
can.run({}, [ctx.ACTION, ctx.COMMAND], function(msg) { can.run({}, [ctx.ACTION, ctx.COMMAND], function(msg) {
msg.result && msg.result[0] && can.field(can, msg, msg.result) msg.result && msg.result[0] && can.field(can, msg, msg.result)
}) })
},
}, function(can) {
can.run = function(event, cmds, cb) { if (cmds[0] == "_search") { return }
var msg = can.request(event, {host: location.host}); msg.detail = can.misc.concat(["page"], cmds)
chrome.runtime.sendMessage(msg, function(res) { can.base.isFunc(cb) && cb(msg.Copy(res)) })
}, can._daemon(can), can._motion(can)
}) }, 1) }) }, 1)

View File

@ -1,9 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/page/cache.css">
<link rel="stylesheet" type="text/css" href="/page/index.css"> <link rel="stylesheet" type="text/css" href="/page/index.css">
</head> </head>
<body style="min-width:800px; min-height:600px; overflow:auto"> <body style="min-width:800px; min-height:600px; overflow:auto">
<script src="/proto.js"></script> <script src="/proto.js"></script>
<script src="/page/cache.js"></script>
<script src="/publish/chrome/popup.js"></script> <script src="/publish/chrome/popup.js"></script>
</body> </body>

View File

@ -1,15 +1,4 @@
Volcanos({name: "popup", iceberg: "http://localhost:9020/chat/", river: { Volcanos({name: "popup", iceberg: "http://localhost:9020/chat/", river: {
serivce: {name: "运营群", storm: {
wx: {name: "公众号 wx", list: [
{name: "微信公众号", help: "wx", index: "web.wiki.word", args: ["usr/icebergs/misc/wx/wx.shy"]},
]},
mp: {name: "小程序 mp", list: [
{name: "微信小程序", help: "mp", index: "web.wiki.word", args: ["usr/icebergs/misc/mp/mp.shy"]},
]},
lark: {name: "机器人 lark", list: [
{name: "飞书机器人", help: "lark", index: "web.wiki.word", args: ["usr/icebergs/misc/lark/lark.shy"]},
]},
}},
product: {name: "产品群", storm: { product: {name: "产品群", storm: {
office: {name: "办公 office", list: [ office: {name: "办公 office", list: [
{name: "feel", help: "影音媒体", index: "web.wiki.feel"}, {name: "feel", help: "影音媒体", index: "web.wiki.feel"},
@ -20,17 +9,6 @@ Volcanos({name: "popup", iceberg: "http://localhost:9020/chat/", river: {
{name: "index", help: "索引", index: "web.wiki.word", args: ["usr/learning/index.shy"]}, {name: "index", help: "索引", index: "web.wiki.word", args: ["usr/learning/index.shy"]},
{name: "context", help: "编程", index: "web.wiki.word", args: ["src/main.shy"]}, {name: "context", help: "编程", index: "web.wiki.word", args: ["src/main.shy"]},
]}, ]},
english: {name: "英汉 english", list: [
{name: "english", help: "英汉", index: "web.wiki.alpha.alpha", args: ["word", "hi"]},
{name: "chinese", help: "汉英", index: "web.wiki.alpha.alpha", args: ["line", "你好"]},
{name: "wubi", help: "五笔", index: "web.code.input.wubi", args: ["word", "wqvb"]},
{name: "wubi", help: "五笔", index: "web.code.input.wubi", args: ["line", "你好"]},
]},
learning: {name: "学习 learning", list: [
{name: "golang", help: "编程", index: "web.wiki.word", args: ["usr/golang-story/src/main.shy"]},
{name: "tmux", help: "粘贴", index: "web.code.tmux.text"},
{name: "study", help: "学习", index: "web.wiki.word", args: ["usr/learning/study.shy"]},
]},
chrome: {name: "爬虫 chrome", list: [ chrome: {name: "爬虫 chrome", list: [
{name: "feel", help: "网页爬虫", index: "web.wiki.feel", args: ["spide/"], feature: { {name: "feel", help: "网页爬虫", index: "web.wiki.feel", args: ["spide/"], feature: {
display: "/plugin/local/wiki/feel.js", display: "/plugin/local/wiki/feel.js",
@ -50,33 +28,6 @@ Volcanos({name: "popup", iceberg: "http://localhost:9020/chat/", river: {
web: {name: "网页 web", list: [ web: {name: "网页 web", list: [
{name: "HTML5", help: "浏览器", index: "web.wiki.word", args: ["usr/icebergs/misc/chrome/chrome.shy"]}, {name: "HTML5", help: "浏览器", index: "web.wiki.word", args: ["usr/icebergs/misc/chrome/chrome.shy"]},
]}, ]},
cli: {name: "命令 cli", list: [
{name: "bash", help: "命令行", index: "web.wiki.word", args: ["usr/icebergs/misc/bash/bash.shy"]},
{name: "git", help: "代码库", index: "web.wiki.word", args: ["usr/icebergs/misc/git/git.shy"]},
{name: "vim", help: "编辑器", index: "web.wiki.word", args: ["usr/icebergs/misc/vim/vim.shy"]},
{name: "tmux", help: "命令行", index: "web.wiki.word", args: ["usr/icebergs/misc/tmux/tmux.shy"]},
]},
linux: {name: "系统 linux", list: [
{name: "idc", help: "平台", index: "web.wiki.word", args: ["usr/linux-story/idc/idc.shy"]},
{name: "iso", help: "系统", index: "web.wiki.word", args: ["usr/linux-story/iso/iso.shy"]},
{name: "iot", help: "设备", index: "web.wiki.word", args: ["usr/linux-story/iot/iot.shy"]},
{name: "cli", help: "命令", index: "web.wiki.word", args: ["usr/linux-story/cli/cli.shy"]},
{name: "linux", help: "系统", index: "web.wiki.word", args: ["usr/linux-story/src/main.shy"]},
]},
nginx: {name: "代理 nginx", list: [
{name: "nginx", help: "代理", index: "web.wiki.word", args: ["usr/nginx-story/src/main.shy"]},
]},
context: {name: "编程 context", list: [
{name: "golang", help: "编程", index: "web.wiki.word", args: ["usr/golang-story/src/main.shy"]},
]},
redis: {name: "缓存 redis", list: [
{name: "redis", help: "缓存", index: "web.wiki.word", args: ["usr/redis-story/src/main.shy"]},
{name: "kafka", help: "队列", index: "web.wiki.word", args: ["usr/redis-story/src/kafka/kafka.shy"]},
]},
mysql: {name: "存储 mysql", list: [
{name: "mysql", help: "数据存储", index: "web.wiki.word", args: ["usr/mysql-story/src/main.shy"]},
{name: "clickhouse", help: "数据存储", index: "web.wiki.word", args: ["usr/mysql-story/src/clickhouse/clickhouse.shy"]},
]},
}}, }},
profile: {name: "测试群", storm: { profile: {name: "测试群", storm: {
release: {name: "发布 release", index: [ release: {name: "发布 release", index: [