1
0
forked from x/ContextOS

add share

This commit is contained in:
shaoying 2019-09-17 21:29:11 +08:00
parent 732a95cbed
commit 4ad2b0e534
12 changed files with 167 additions and 136 deletions

View File

@ -189,7 +189,7 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
if p == "" {
// 所有节点
m.Confm("auth", func(k string, node map[string]interface{}) {
if i > len(arg)-1 || node["type"].(string) == arg[i] || strings.HasSuffix(k, arg[i]) || strings.HasPrefix(k, arg[i]) {
if t, _ := node["type"].(string); i > len(arg)-1 || t == arg[i] || strings.HasSuffix(k, arg[i]) || strings.HasPrefix(k, arg[i]) {
m.Push("create_time", node["create_time"])
m.Push("key", k)
m.Push("type", node["type"])
@ -623,12 +623,14 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
case "check":
if relay := m.Confm("auth", []string{rid, "data"}); relay != nil {
if kit.Select("", arg, 1) == "userrole" && kit.Int(relay["count"]) > 0 {
relay["count"] = kit.Int(relay["count"]) - 1
m.Echo("%s", relay["userrole"])
}
for k, v := range relay {
m.Append(k, v)
}
if kit.Int(relay["count"]) > 0 {
relay["count"] = kit.Int(relay["count"]) - 1
}
}
// 分享权限
@ -637,16 +639,17 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
m.Cmdy("aaa.auth", "username", m.Option("username"), "relay")
break
}
m.Cmdy("aaa.auth", "username", m.Option("username"), "relay", arg[1], "data",
"userrole", kit.Select("tech", arg, 2),
"username", kit.Select("", arg, 3),
"count", kit.Select("1", arg, 4),
)
relay := m.Cmdx("aaa.auth", "username", m.Option("username"), "relay", arg[1])
m.Cmd("aaa.auth", relay, "data", "from", m.Option("username"), "count", "1", arg[2:])
m.Echo(relay)
// 授权计数
case "count":
m.Cmdy("aaa.auth", rid, "data", "count", kit.Select("1", arg, 1))
case "clear":
m.Cmdy("aaa.auth", "relay")
default:
m.Cmdy("aaa.auth", rid, "data", arg)
}

View File

@ -4,5 +4,5 @@ var version = struct {
host string
self int
}{
"2019-09-16 21:57:16", "centos", 508,
"2019-09-17 20:58:54", "centos", 526,
}

View File

@ -312,7 +312,7 @@ func (m *Message) Table(cbs ...interface{}) *Message {
for i := 0; i < nrow; i++ {
line := map[string]string{}
for _, k := range m.Meta["append"] {
line[k] = m.Meta[k][i]
line[k] = kit.Select("", m.Meta[k], i)
}
switch cb := cbs[0].(type) {

View File

@ -86,7 +86,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
"index": []interface{}{
map[string]interface{}{"name": "ifconfig", "help": "网卡",
"tmpl": "componet", "view": "", "init": "",
"type": "private", "ctx": "ssh", "cmd": "_route",
"type": "protected", "ctx": "ssh", "cmd": "_route",
"args": []interface{}{"_", "tcp.ifconfig"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "value": "", "imports": "plugin_pod"},
map[string]interface{}{"type": "button", "value": "查看", "action": "auto"},
@ -94,7 +94,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
},
map[string]interface{}{"name": "proc", "help": "进程",
"tmpl": "componet", "view": "", "init": "",
"type": "private", "ctx": "ssh", "cmd": "_route",
"type": "protected", "ctx": "ssh", "cmd": "_route",
"args": []interface{}{"_", "cli.proc"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "value": "", "imports": "plugin_pod"},
map[string]interface{}{"type": "text", "name": "arg", "value": ""},
@ -104,7 +104,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
},
map[string]interface{}{"name": "spide", "help": "爬虫",
"tmpl": "componet", "view": "Context", "init": "",
"type": "private", "ctx": "ssh", "cmd": "_route",
"type": "protected", "ctx": "ssh", "cmd": "_route",
"args": []interface{}{"_", "context", "web", "spide"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "imports": "plugin_pod"},
map[string]interface{}{"type": "button", "value": "执行"},
@ -113,7 +113,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
},
map[string]interface{}{"name": "post", "help": "请求",
"tmpl": "componet", "view": "Context", "init": "",
"type": "private", "ctx": "ssh", "cmd": "_route",
"type": "protected", "ctx": "ssh", "cmd": "_route",
"args": []interface{}{"_", "web.post", "__", "content_type", "application/json", "parse", "json"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "imports": "plugin_pod"},
map[string]interface{}{"type": "text", "name": "spide", "value": "dev", "imports": "plugin_site"},
@ -123,7 +123,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
},
map[string]interface{}{"name": "get", "help": "请求",
"tmpl": "componet", "view": "Context", "init": "",
"type": "private", "ctx": "ssh", "cmd": "_route",
"type": "protected", "ctx": "ssh", "cmd": "_route",
"args": []interface{}{"_", "web.get", "__", "method", "GET", "parse", "json"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "imports": "plugin_pod"},
map[string]interface{}{"type": "text", "name": "spide", "value": "dev", "imports": "plugin_site"},

View File

@ -111,13 +111,28 @@ func (web *WEB) Login(msg *ctx.Message, w http.ResponseWriter, r *http.Request)
return false
} else if msg.Options("relay") {
if relay := msg.Cmd("aaa.relay", "check", msg.Option("relay")); relay.Appends("username") {
if role := msg.Cmdx("aaa.relay", "check", msg.Option("relay"), "userrole"); role != "" {
msg.Log("info", "login: %s", msg.Option("username", relay.Append("username")))
http.SetCookie(w, &http.Cookie{Name: "sessid", Value: msg.Option("sessid", msg.Cmdx("aaa.user", "session", "select")), Path: "/"})
msg.Cmd("aaa.role", role, "user", msg.Option("username"))
msg.Log("info", "relay: %s", role)
return true
relay := msg.Cmd("aaa.relay", "check", msg.Option("relay"))
if relay.Appendi("count") < 1 {
msg.Err("共享失效")
return false
}
if relay.Appends("username") {
msg.Log("info", "login: %s", msg.Option("username", relay.Append("username")))
http.SetCookie(w, &http.Cookie{Name: "sessid", Value: msg.Option("sessid", msg.Cmdx("aaa.user", "session", "select")), Path: "/"})
}
if role := relay.Append("userrole"); role != "" {
msg.Cmd("aaa.role", role, "user", msg.Option("username"))
msg.Log("info", "relay: %s", role)
}
if relay.Appends("url") {
msg.Append("redirect", relay.Append("url"))
return false
}
if relay.Appends("form") {
form := kit.UnMarshalm(relay.Append("form"))
for k, v := range form {
msg.Log("info", "form %s:%s", k, msg.Option(k, kit.Format(v)))
}
}
}

View File

@ -92,7 +92,14 @@ var Index = &ctx.Context{Name: "chat", Help: "会议中心",
if len(arg) > 0 {
switch arg[0] {
// 用户昵称
case "share":
m.Append("qrcode", arg[1])
return
case "relay":
relay := m.Cmdx("aaa.relay", "share", arg[1:])
m.Log("info", "relay: %s", relay)
m.Echo(relay)
return
case "rename":
m.Cmd("aaa.auth", "username", m.Option("username"), "data", "nickname", arg[1])
}

View File

@ -1,5 +1,4 @@
var page = Page({
check: true,
var page = Page({check: true,
conf: {refresh: 1000, border: 4, layout: {header:30, river:120, action:180, source:60, storm:100, footer:30}},
onlayout: function(event, sizes) {
var page = this
@ -22,12 +21,17 @@ var page = Page({
page.river.Pane.Size(sizes.river, height)
page.storm.Pane.Size(sizes.storm, height)
var full = false
if (kit.device.isMobile && sizes.action == -1) {
full = true
}
sizes.action == undefined && (sizes.action = page.action.clientHeight)
sizes.source == undefined && (sizes.source = page.source.clientHeight);
(sizes.action == -1 || sizes.source == 0) && (sizes.action = height, sizes.source = 0)
width -= page.river.offsetWidth+page.storm.offsetWidth
page.action.Pane.Size(width, sizes.action)
full && (page.action.style.height = "")
page.source.Pane.Size(width, sizes.source)
height -= page.source.offsetHeight+page.action.offsetHeight
@ -192,8 +196,18 @@ var page = Page({
"创建": function(event) {
page.ocean.Pane.Show()
},
"共享": function(event) {
page.login.Pane.Run(["relay", "river", "username", kit.prompt("分享给用户"), "url", ctx.Share({
"river": page.river.Pane.which.get(),
"layout": page.action.Pane.Layout(),
})], function(msg) {
page.ontoast({text: location.origin+location.pathname+"?relay="+msg.result.join(""), title: "共享链接", button: ["确定"], cb: function(which) {
page.ontoast()
}})
})
},
},
Button: ["创建"],
Button: ["创建", "共享"],
}
},
initTarget: function(page, field, option, output) {
@ -275,7 +289,7 @@ var page = Page({
var plugin = event.Plugin || {}, engine = {
share: function(args) {
typeof cbs == "function" && cbs(ctx.Share({"group": option.dataset.group, "name": option.dataset.name, "cmds": [
river, line.group, line.index, args[1]||"",
river, line.storm, line.action, args[1]||"",
]}))
return true
},
@ -481,8 +495,20 @@ var page = Page({
"创建": function(event) {
page.steam.Pane.Show()
},
"共享": function(event) {
page.login.Pane.Run(["relay", "storm", "username", kit.prompt("分享给用户"), "url", ctx.Share({
"river": page.river.Pane.which.get(),
"storm": page.storm.Pane.which.get(),
"layout": page.action.Pane.Layout(),
})], function(msg) {
var url = location.origin+location.pathname+"?relay="+msg.result.join("")
page.ontoast({text: "<img src=\""+ctx.Share({"group": "index", "name": "login", cmds: ["share", url]})+"\">", height: 320, title: url, button: ["确定"], cb: function(which) {
page.ontoast()
}})
})
},
},
Button: ["创建"],
Button: ["创建", "共享"],
}
},
initSteam: function(page, field, option, output) {
@ -490,7 +516,7 @@ var page = Page({
var table = kit.AppendChild(output, "table")
var device = kit.AppendChild(field, [{"view": ["device", "table"]}]).last
var ui = kit.AppendChild(field, [{view: ["create"], list: [
{input: ["name", function(event) {
{data: {title: "应用名称"}, input: ["name", function(event) {
page.oninput(event, function(event) {
switch (event.key) {
case "i":
@ -529,7 +555,7 @@ var page = Page({
}
}), event.key == "Enter" && this.nextSibling.click()
}]}, {button: ["create", function(event) {
}]}, {button: ["创建", function(event) {
if (!ui.name.value) {ui.name.focus(); return}
var list = []
@ -543,7 +569,7 @@ var page = Page({
field.Pane.Create(ui.name.value, list)
}]}, {name: "list", view: ["list", "table"]},
}]}, {name: "list", view: ["list", "table"], style: {"min-width": "240px"}, list: [{type: "caption", inner: "3. 已选命令列表"}]},
]}])
return {
@ -555,12 +581,14 @@ var page = Page({
}]).last
},
Update: function(list, pod) {var pane = field.Pane
device.innerHTML = "", kit.AppendTable(device, list, ["key", "index", "name", "help"], function(value, key, com, i, tr, event) {
kit.AppendChilds(device, [{type: "caption", inner: "2. 选择模块命令 ->"}])
kit.AppendTable(device, list, ["key", "index", "name", "help"], function(value, key, com, i, tr, event) {
pane.Append(com, pod)
})
},
Select: function(list) {var pane = field.Pane
table.innerHTML = "", kit.AppendTable(table, list, ["user", "node"], function(value, key, pod, i, tr, event) {
kit.AppendChilds(table, [{type: "caption", inner: "1. 选择用户节点 ->"}])
kit.AppendTable(table, list, ["user", "node"], function(value, key, pod, i, tr, event) {
var old = table.querySelector("tr.select")
tr.className = "select", old && (old.className = "normal"), pane.Run([river, pod.user, pod.node], function(msg) {
pane.Update(ctx.Table(msg), pod)

View File

@ -1,14 +1,13 @@
ctx = context = {
Run: function(page, dataset, cmd, cb) {
Run: function(dataset, cmd, cb) {
var option = {"cmds": cmd}
for (var k in dataset) {
option[k] = dataset[k].split(",")
}
var event = window.event
kit.History.add("cmd", option)
this.GET("", option, function(msg) {
this.POST("", option, function(msg) {
msg[0] && (msg = msg[0])
// msg && (msg.__proto__ = (page || {}))
msg.Result = msg.result? msg.result.join(""): ""
msg.Results = function() {
var s = msg.Result
@ -21,7 +20,7 @@ ctx = context = {
typeof cb == "function" && cb(msg || {})
})
},
Runs: function(page, form, cb) {
Runs: function(form, cb) {
var data = {}
for (var key in form.dataset) {
data[key] = form.dataset[key]
@ -31,7 +30,7 @@ ctx = context = {
data[form[i].name] = form[i].value
}
}
this.Run(page, data, [], cb || form.ondaemon)
this.Run(data, [], cb || form.ondaemon)
},
Table: function(msg, cb) {
var ret = []
@ -106,12 +105,37 @@ ctx = context = {
return location.origin+location.pathname+"?"+arg
},
Current: function(key, value) {
context.GET("", {
"group": "index",
"name": "cmd",
"cmds": ["sess", "current", key, value],
})
Search: function(key, value) {
var args = {}
var search = location.search.split("?")
if (search.length > 1) {
var searchs = search[1].split("&")
for (var i = 0; i < searchs.length; i++) {
var keys = searchs[i].split("=")
if (keys[1] == "") {continue}
args[keys[0]] = decodeURIComponent(keys[1])
}
}
if (key == undefined) {
return args
} else if (typeof key == "object") {
for (var k in key) {
if (key[k] != undefined) {
args[k] = key[k]
}
}
} else if (value == undefined) {
return args[key] || this.Cookie(key)
} else {
args[key] = value
}
var arg = []
for (var k in args) {
arg.push(k+"="+encodeURIComponent(args[k]))
}
location.search = arg.join("&");
return value
},
Cookie: function(key, value) {
@ -130,77 +154,27 @@ ctx = context = {
}
return this.Cookie()
}
if (value == undefined) {
var pattern = new RegExp(key+"=([^;]*);?");
var result = pattern.exec(document.cookie);
if (result && result.length > 0) {
return result[1];
}
return "";
var pattern = new RegExp(key+"=([^;]*);?")
var result = pattern.exec(document.cookie)
return result && result.length > 0? result[1]: ""
}
document.cookie = key+"="+value+";path=/";
return this.Cookie(key);
document.cookie = key+"="+value+";path=/"
return this.Cookie(key)
},
Search: function(key, value) {
var args = {};
var search = location.search.split("?");
if (search.length > 1) {
var searchs = search[1].split("&");
for (var i = 0; i < searchs.length; i++) {
var keys = searchs[i].split("=");
if (keys[1]=="") {
continue
}
args[keys[0]] = decodeURIComponent(keys[1]);
}
}
if (key == undefined) {
return args
} else if (typeof key == "object") {
for (var k in key) {
if (key[k] != undefined) {
args[k] = key[k];
}
}
} else if (value == undefined) {
return args[key] || this.Cookie(key);
} else {
args[key] = value;
}
var arg = [];
for (var k in args) {
arg.push(k+"="+encodeURIComponent(args[k]));
}
location.search = arg.join("&");
return value
},
GET: function(url, form, cb) {
form = form || {}
var args = [];
POST: function(url, form, cb) {
var args = []
for (var k in form) {
if (form[k] instanceof Array) {
for (i in form[k]) {
args.push(k+"="+encodeURIComponent(form[k][i]));
args.push(k+"="+encodeURIComponent(form[k][i]))
}
} else if (form[k] != undefined) {
args.push(k+"="+encodeURIComponent(form[k]));
args.push(k+"="+encodeURIComponent(form[k]))
}
}
var arg = args.join("&");
// arg && (url += ((url.indexOf("?")>-1)? "&": "?") + arg)
var xhr = new XMLHttpRequest();
// xhr.open("POST", url);
xhr.open("POST", url);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
xhr.setRequestHeader("Accept", "application/json")
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) {
return
@ -224,6 +198,10 @@ ctx = context = {
}
typeof cb == "function" && cb(msg)
}
xhr.send(arg);
xhr.open("POST", url)
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
xhr.setRequestHeader("Accept", "application/json")
xhr.send(args.join("&"))
},
}

View File

@ -216,14 +216,15 @@ function Page(page) {
},
ontoast: function(text, title, duration) {
// {text, title, duration, inputs, buttons}
if (!text) {page.toast.style.display = "none"; return}
var args = typeof text == "object"? text: {text: text, title: title, duration: duration}
var toast = kit.ModifyView("fieldset.toast", {
display: "block", dialog: [args.width||text.length*10+100, args.height||60], padding: 10,
display: "block", dialog: [args.width||text.length*10+100, args.height||80], padding: 10,
})
if (!text) {toast.style.display = "none"; return}
if (!args.duration && args.button) {args.duration = -1}
var list = [{text: [title||"", "div", "title"]}, {text: [args.text||"", "div", "content"]}]
var list = [{text: [args.title||"", "div", "title"]}, {text: [args.text||"", "div", "content"]}]
args.inputs && args.inputs.forEach(function(input) {
if (typeof input == "string") {
list.push({inner: input, type: "label", style: {"margin-right": "5px"}})
@ -645,7 +646,7 @@ function Pane(page, field) {
})
},
Run: function(cmds, cb) {
ctx.Run(page, option.dataset, cmds, cb||pane.ondaemon)
ctx.Run(option.dataset, cmds, cb||pane.ondaemon)
},
Size: function(width, height) {

View File

@ -274,7 +274,7 @@ kit = toolkit = {
child.view.length > 3 && (child.name = child.view[3])
} else if (child.text) {
child.data["innerText"] = child.text[0]
child.data["innerHTML"] = child.text[0]
child.type = child.text.length > 1? child.text[1]: "pre"
child.text.length > 2 && (child.data["className"] = child.text[2])

View File

@ -53,7 +53,7 @@ var page = Page({
page.onlayout()
})
ctx.Runs(page, form, function(msg) {
ctx.Runs(form, function(msg) {
ui.back.innerHTML = "", kit.AppendChild(ui.back, [
{"button": ["知识", function(event) {
ctx.Search({"level": "", "class": "", "favor": ""})
@ -129,7 +129,7 @@ var page = Page({
ctx.Search("layout") == "max" && (page.Conf("tree.display", "none"), page.Conf("menu.display", "none"))
ctx.Runs(page, form, function(msg) {
ctx.Runs(form, function(msg) {
ui.menu.innerHTML = "", ui.text.innerHTML = msg.result? msg.result.join(""): ""
kit.AppendChild(ui.menu, [{"tree": kit.OrderText(field, ui.text)}])
page.footer.Pane.State("count", msg.visit_count)

View File

@ -22,7 +22,7 @@ $ export ctx_dev=https://shylinux.com; curl $ctx_dev/publish/boot.sh | bash -s i
```
*install后面的参数context就是指定的下载目录如不指定会把相关文件下载到当前目录。*
*ctx_dev环境变量指定服务器地址所以可以自行搭建服务器。*
*ctx_dev环境变量指定服务器地址所以可以自行搭建服务器。*
### 启动
下载完成后会自动启动context
@ -66,30 +66,29 @@ time size line path
- var目录就是各种输出文件如日志与缓存文件
- usr目录就是各种前端文件与数据如js、css文件
*如需要自行启动context必须在当前目录然后运行bin/boot.sh脚本。否则会找不到相关文件。*
*如需要自行启动context必须进入下载后的目录中然后运行bin/boot.sh脚本。否则会找不到相关文件。*
quit命令退出context
```
4[22:21:20]nfs> quit
quit, wait 1s
time code
2019-09-17 10:29:59 0
4[22:21:20]nfs>
$
```
*如果需要搭建私有服务可以直接运行bin/zone.sh启动根服务节点。*
## 基本功能
除了命令行交互,还可以访问<http://localhost:9095>,用浏览器进行操作。
context启动后默认监听9095端口启动网页服务。
进入下载目录,可以看到的有八个文件。
在bin目录下就是各种执行文件
- bin/benchcontext的执行程序
- bin/boot.shcontext的启动脚本
- bin/zone.sh启动区域节点
- bin/user.sh启动用户节点
- bin/node.sh启动工作节点
context内部实现了语法解析通过自定义的脚本语言实现功能的灵活控制。
在etc目录下就是context执行过程中用到的脚本。
- etc/init.shy启动时加载的脚本
- etc/exit.shy结束时运行的脚本
- etc/common.shyinit.shy调用到的脚本
## 快速共享
点击左上角的标题,会跳转到当面页面的完整链接地址。
把主机地址替换成别人可以访问的IP就共享给其它用户。
其它用户,输入用户与密码即可登录,并加入此群聊中,使用当前功能页面。
## 创建集群
context是一种分布式框架可以运行在任意设备上并且实现了自动组网、自动路由、自动认证。
@ -183,24 +182,24 @@ D:\context\world/var
D:\context\hello/var D:\context\hello/var
```
## 团队使用
### 团队使用
context也可以支持团队协作使用这时候就需要将区域节点部署到公共主机上。
区域节点的作用就是生成动态域名,分发路由,解决命名冲突,与权限分配等功能。
### 启动用户节点
#### 启动用户节点
在公共主机上启动区域节点后,每个组员就可以在自己主机上启动用户节点,但需要指定区域节点的地址。
如下命令ip换成自己的公共主机9095端口保留这是context默认的web端口。
```
$ ctx_dev=http://192.168.88.102:9095 bin/user.sh
```
### 启动工作节点
#### 启动工作节点
同样每个用户都可以启动多用工作节点。
```
$ bin/node.sh create world
```
### 启动团队协作
#### 启动团队协作
当有多个用户连接到公共节点后,用户与用户之间就可以相互访问对方的所有节点。
但是默认启用了节点认证,所有命令都没有权限。所以调用对应节点上的命令,需要对方开启命令权限。
@ -208,7 +207,7 @@ $ bin/node.sh create world
从而实现安全快速的资源共享。
## 启动分机节点
### 启动分机节点
当区域的用户节点过多,就可以启动分机节点。
启动分机节点,只需要指定上级节点即可。
用户在连接公共节点时指定这个新节点的ip即可。