diff --git a/src/contexts/aaa/aaa.go b/src/contexts/aaa/aaa.go index 86fa54ff..25801a4e 100644 --- a/src/contexts/aaa/aaa.go +++ b/src/contexts/aaa/aaa.go @@ -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) } diff --git a/src/contexts/cli/version.go b/src/contexts/cli/version.go index 86427f55..b4bbdac6 100644 --- a/src/contexts/cli/version.go +++ b/src/contexts/cli/version.go @@ -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, } diff --git a/src/contexts/ctx/type.go b/src/contexts/ctx/type.go index ffb404a4..753b2a4f 100644 --- a/src/contexts/ctx/type.go +++ b/src/contexts/ctx/type.go @@ -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) { diff --git a/src/contexts/ssh/ssh.go b/src/contexts/ssh/ssh.go index 6e8d74f7..67487895 100644 --- a/src/contexts/ssh/ssh.go +++ b/src/contexts/ssh/ssh.go @@ -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"}, diff --git a/src/contexts/web/web.go b/src/contexts/web/web.go index 24193e09..cac5afd5 100644 --- a/src/contexts/web/web.go +++ b/src/contexts/web/web.go @@ -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))) } } } diff --git a/src/examples/chat/chat.go b/src/examples/chat/chat.go index 68253ed9..87266a9b 100644 --- a/src/examples/chat/chat.go +++ b/src/examples/chat/chat.go @@ -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]) } diff --git a/usr/librarys/chat.js b/usr/librarys/chat.js index eed9fbe3..8ed2b829 100644 --- a/usr/librarys/chat.js +++ b/usr/librarys/chat.js @@ -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: "", 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) diff --git a/usr/librarys/context.js b/usr/librarys/context.js index 17e75625..a7dfd07e 100644 --- a/usr/librarys/context.js +++ b/usr/librarys/context.js @@ -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("&")) }, } diff --git a/usr/librarys/example.js b/usr/librarys/example.js index 49eed353..77fdc0aa 100644 --- a/usr/librarys/example.js +++ b/usr/librarys/example.js @@ -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) { diff --git a/usr/librarys/toolkit.js b/usr/librarys/toolkit.js index 7073cad3..9b02ef3b 100644 --- a/usr/librarys/toolkit.js +++ b/usr/librarys/toolkit.js @@ -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]) diff --git a/usr/librarys/wiki.js b/usr/librarys/wiki.js index ce84b13c..947e0113 100644 --- a/usr/librarys/wiki.js +++ b/usr/librarys/wiki.js @@ -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) diff --git a/usr/local/wiki/自然/编程/index.md b/usr/local/wiki/自然/编程/index.md index a13a01f7..5e433cf4 100644 --- a/usr/local/wiki/自然/编程/index.md +++ b/usr/local/wiki/自然/编程/index.md @@ -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,启动根服务节点。* ## 基本功能 除了命令行交互,还可以访问,用浏览器进行操作。 context启动后,默认监听9095端口,启动网页服务。 -进入下载目录,可以看到的有八个文件。 - -在bin目录下,就是各种执行文件 - -- bin/bench,context的执行程序 -- bin/boot.sh,context的启动脚本 -- bin/zone.sh,启动区域节点 -- bin/user.sh,启动用户节点 -- bin/node.sh,启动工作节点 - -context内部实现了语法解析,通过自定义的脚本语言,实现功能的灵活控制。 - -在etc目录下,就是context执行过程中用到的脚本。 - -- etc/init.shy,启动时加载的脚本 -- etc/exit.shy,结束时运行的脚本 -- etc/common.shy,init.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即可。