diff --git a/猿人学练习/5js加密js第十五节实战例题jsRPC/README.md b/猿人学练习/5js加密js第十五节实战例题jsRPC/README.md
new file mode 100644
index 0000000..128c8e1
--- /dev/null
+++ b/猿人学练习/5js加密js第十五节实战例题jsRPC/README.md
@@ -0,0 +1,40 @@
+# 知识点:sekiro rpc框架
+1. https://sekiro.iinti.cn/sekiro-doc/01_user_manual/1.quickstart.html#%E6%B5%8F%E8%A7%88%E5%99%A8js%E7%8E%AF%E5%A2%83
+2. https://blog.csdn.net/qq_43502467/article/details/129456814
+
+## 简单测试
+安装sekiro rpc框架
+
+ https://oss.iinti.cn/sekiro
+
+运行启动脚本
+
+ bin/sekiro.sh :mac or linux
+ bin/sekiro.bat :windows
+
+
+
+编写注入浏览器的代码
+
+./test.js 文件
+
+将`test.js`文件中js注入到浏览器中
+
+
+
+浏览器打开如下地址
+
+ http://127.0.0.1:5612/business/groupList
+
+可以看到当前系统有哪些注册过的group
+
+
+
+通过js注入把网页数据反回给接口
+
+ http://127.0.0.1:5612/business/invoke?group=ayf-ws&action=clientTime
+
+## 解题
+
+vip视频14
+
diff --git a/猿人学练习/5js加密js第十五节实战例题jsRPC/challenge5.js b/猿人学练习/5js加密js第十五节实战例题jsRPC/challenge5.js
new file mode 100644
index 0000000..76b0e6b
--- /dev/null
+++ b/猿人学练习/5js加密js第十五节实战例题jsRPC/challenge5.js
@@ -0,0 +1,166 @@
+function SekiroClient(e) {
+ if (this.wsURL = e, this.handlers = {}, this.socket = {}, !e) throw new Error("wsURL can not be empty!!");
+ this.webSocketFactory = this.resolveWebSocketFactory(), this.connect()
+}
+
+SekiroClient.prototype.resolveWebSocketFactory = function () {
+ if ("object" == typeof window) {
+ var e = window.WebSocket ? window.WebSocket : window.MozWebSocket;
+ return function (o) {
+ function t(o) {
+ this.mSocket = new e(o)
+ }
+
+ return t.prototype.close = function () {
+ this.mSocket.close()
+ }, t.prototype.onmessage = function (e) {
+ this.mSocket.onmessage = e
+ }, t.prototype.onopen = function (e) {
+ this.mSocket.onopen = e
+ }, t.prototype.onclose = function (e) {
+ this.mSocket.onclose = e
+ }, t.prototype.send = function (e) {
+ this.mSocket.send(e)
+ }, new t(o)
+ }
+ }
+ if ("object" == typeof weex) try {
+ console.log("test webSocket for weex");
+ var o = weex.requireModule("webSocket");
+ return console.log("find webSocket for weex:" + o), function (e) {
+ try {
+ o.close()
+ } catch (e) {
+ }
+ return o.WebSocket(e, ""), o
+ }
+ } catch (e) {
+ console.log(e)
+ }
+ if ("object" == typeof WebSocket) return function (o) {
+ return new e(o)
+ };
+ throw new Error("the js environment do not support websocket")
+}, SekiroClient.prototype.connect = function () {
+ console.log("sekiro: begin of connect to wsURL: " + this.wsURL);
+ var e = this;
+ try {
+ this.socket = this.webSocketFactory(this.wsURL)
+ } catch (o) {
+ return console.log("sekiro: create connection failed,reconnect after 2s:" + o), void setTimeout(function () {
+ e.connect()
+ }, 2e3)
+ }
+ this.socket.onmessage(function (o) {
+ e.handleSekiroRequest(o.data)
+ }), this.socket.onopen(function (e) {
+ console.log("sekiro: open a sekiro client connection")
+ }), this.socket.onclose(function (o) {
+ console.log("sekiro: disconnected ,reconnection after 2s"), setTimeout(function () {
+ e.connect()
+ }, 2e3)
+ })
+}, SekiroClient.prototype.handleSekiroRequest = function (e) {
+ console.log("receive sekiro request: " + e);
+ var o = JSON.parse(e), t = o.__sekiro_seq__;
+ if (o.action) {
+ var n = o.action;
+ if (this.handlers[n]) {
+ var s = this.handlers[n], i = this;
+ try {
+ s(o, function (e) {
+ try {
+ i.sendSuccess(t, e)
+ } catch (e) {
+ i.sendFailed(t, "e:" + e)
+ }
+ }, function (e) {
+ i.sendFailed(t, e)
+ })
+ } catch (e) {
+ console.log("error: " + e), i.sendFailed(t, ":" + e)
+ }
+ } else this.sendFailed(t, "no action handler: " + n + " defined")
+ } else this.sendFailed(t, "need request param {action}")
+}, SekiroClient.prototype.sendSuccess = function (e, o) {
+ var t;
+ if ("string" == typeof o) try {
+ t = JSON.parse(o)
+ } catch (e) {
+ (t = {}).data = o
+ } else "object" == typeof o ? t = o : (t = {}).data = o;
+ (Array.isArray(t) || "string" == typeof t) && (t = {
+ data: t,
+ code: 0
+ }), t.code ? t.code = 0 : (t.status, t.status = 0), t.__sekiro_seq__ = e;
+ var n = JSON.stringify(t);
+ console.log("response :" + n), this.socket.send(n)
+}, SekiroClient.prototype.sendFailed = function (e, o) {
+ "string" != typeof o && (o = JSON.stringify(o));
+ var t = {};
+ t.message = o, t.status = -1, t.__sekiro_seq__ = e;
+ var n = JSON.stringify(t);
+ console.log("sekiro: response :" + n), this.socket.send(n)
+}, SekiroClient.prototype.registerAction = function (e, o) {
+ if ("string" != typeof e) throw new Error("an action must be string");
+ if ("function" != typeof o) throw new Error("a handler must be function");
+ return console.log("sekiro: register action: " + e), this.handlers[e] = o, this
+};
+
+
+var client = new SekiroClient("ws://127.0.0.1:5612/business/register?group=ayf-ws&clientId=" + Math.random());
+client.registerAction("getData", function (request, resolve, reject) {
+ numi = request.page;
+ var url = "/api/challenge5";
+ call = function(num) {
+ var list = {
+ "page": String(num),
+ "token": window.token,
+ };
+ $.ajax({
+ url: url,
+ dataType: "json",
+ async: true,
+ data: list,
+ type: "POST",
+ beforeSend: function(request) {
+ (function() {
+ var httpRequest = new XMLHttpRequest();
+ var url = '/cityjson';
+ httpRequest.open('POST', url, false);
+ httpRequest.send()
+ }
+ )()
+ },
+ success: function(data) {
+ window[data.k['k'].split('|')[0]] = parseInt(data.k['k'].split('|')[1]);
+ var s = '
';
+ datas = data.data;
+ resolve(datas);
+ $.each(datas, function(index, val) {
+ var html = '' + val.value + ' | ';
+ s += html
+ });
+ $('.data').text('').append(s + '
')
+ },
+ complete: function() {
+ $("#page").paging({
+ nowPage: num,
+ pageNum: 100,
+ buttonNum: 7,
+ canJump: 1,
+ showOne: 1,
+ callback: function(num) {
+ call(num)
+ },
+ })
+ },
+ error: function() {
+ alert('加载失败败')
+ location.reload()
+ }
+ })
+ }
+ ;
+ call(numi)
+});
\ No newline at end of file
diff --git a/猿人学练习/5js加密js第十五节实战例题jsRPC/img/1.png b/猿人学练习/5js加密js第十五节实战例题jsRPC/img/1.png
new file mode 100644
index 0000000..308aa83
Binary files /dev/null and b/猿人学练习/5js加密js第十五节实战例题jsRPC/img/1.png differ
diff --git a/猿人学练习/5js加密js第十五节实战例题jsRPC/img/2.png b/猿人学练习/5js加密js第十五节实战例题jsRPC/img/2.png
new file mode 100644
index 0000000..4e860fc
Binary files /dev/null and b/猿人学练习/5js加密js第十五节实战例题jsRPC/img/2.png differ
diff --git a/猿人学练习/5js加密js第十五节实战例题jsRPC/img/3.png b/猿人学练习/5js加密js第十五节实战例题jsRPC/img/3.png
new file mode 100644
index 0000000..dbb56a1
Binary files /dev/null and b/猿人学练习/5js加密js第十五节实战例题jsRPC/img/3.png differ
diff --git a/猿人学练习/5js加密js第十五节实战例题jsRPC/main.py b/猿人学练习/5js加密js第十五节实战例题jsRPC/main.py
new file mode 100644
index 0000000..526409f
--- /dev/null
+++ b/猿人学练习/5js加密js第十五节实战例题jsRPC/main.py
@@ -0,0 +1,29 @@
+import requests
+import json
+
+
+def challenge5(page):
+ url = f"http://127.0.0.1:5612/business/invoke?group=ayf-ws&action=getData&page={page}"
+ session = requests.session()
+ headers = {
+ 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
+ }
+ session.headers = headers
+ response = session.request("GET", url)
+ return response.text
+
+
+def run():
+ data_num = 0
+ for page in range(1, 101):
+ response_text = challenge5(page)
+ res_dict = json.loads(response_text)
+ data_list = res_dict.get('data')
+ print(data_list)
+ for data in data_list:
+ data_num += int(data.get('value'))
+ print(data_num)
+
+
+if __name__ == '__main__':
+ run()
diff --git a/猿人学练习/5js加密js第十五节实战例题jsRPC/test.js b/猿人学练习/5js加密js第十五节实战例题jsRPC/test.js
new file mode 100644
index 0000000..6ff8c91
--- /dev/null
+++ b/猿人学练习/5js加密js第十五节实战例题jsRPC/test.js
@@ -0,0 +1,114 @@
+function SekiroClient(e) {
+ if (this.wsURL = e, this.handlers = {}, this.socket = {}, !e) throw new Error("wsURL can not be empty!!");
+ this.webSocketFactory = this.resolveWebSocketFactory(), this.connect()
+}
+
+SekiroClient.prototype.resolveWebSocketFactory = function () {
+ if ("object" == typeof window) {
+ var e = window.WebSocket ? window.WebSocket : window.MozWebSocket;
+ return function (o) {
+ function t(o) {
+ this.mSocket = new e(o)
+ }
+
+ return t.prototype.close = function () {
+ this.mSocket.close()
+ }, t.prototype.onmessage = function (e) {
+ this.mSocket.onmessage = e
+ }, t.prototype.onopen = function (e) {
+ this.mSocket.onopen = e
+ }, t.prototype.onclose = function (e) {
+ this.mSocket.onclose = e
+ }, t.prototype.send = function (e) {
+ this.mSocket.send(e)
+ }, new t(o)
+ }
+ }
+ if ("object" == typeof weex) try {
+ console.log("test webSocket for weex");
+ var o = weex.requireModule("webSocket");
+ return console.log("find webSocket for weex:" + o), function (e) {
+ try {
+ o.close()
+ } catch (e) {
+ }
+ return o.WebSocket(e, ""), o
+ }
+ } catch (e) {
+ console.log(e)
+ }
+ if ("object" == typeof WebSocket) return function (o) {
+ return new e(o)
+ };
+ throw new Error("the js environment do not support websocket")
+}, SekiroClient.prototype.connect = function () {
+ console.log("sekiro: begin of connect to wsURL: " + this.wsURL);
+ var e = this;
+ try {
+ this.socket = this.webSocketFactory(this.wsURL)
+ } catch (o) {
+ return console.log("sekiro: create connection failed,reconnect after 2s:" + o), void setTimeout(function () {
+ e.connect()
+ }, 2e3)
+ }
+ this.socket.onmessage(function (o) {
+ e.handleSekiroRequest(o.data)
+ }), this.socket.onopen(function (e) {
+ console.log("sekiro: open a sekiro client connection")
+ }), this.socket.onclose(function (o) {
+ console.log("sekiro: disconnected ,reconnection after 2s"), setTimeout(function () {
+ e.connect()
+ }, 2e3)
+ })
+}, SekiroClient.prototype.handleSekiroRequest = function (e) {
+ console.log("receive sekiro request: " + e);
+ var o = JSON.parse(e), t = o.__sekiro_seq__;
+ if (o.action) {
+ var n = o.action;
+ if (this.handlers[n]) {
+ var s = this.handlers[n], i = this;
+ try {
+ s(o, function (e) {
+ try {
+ i.sendSuccess(t, e)
+ } catch (e) {
+ i.sendFailed(t, "e:" + e)
+ }
+ }, function (e) {
+ i.sendFailed(t, e)
+ })
+ } catch (e) {
+ console.log("error: " + e), i.sendFailed(t, ":" + e)
+ }
+ } else this.sendFailed(t, "no action handler: " + n + " defined")
+ } else this.sendFailed(t, "need request param {action}")
+}, SekiroClient.prototype.sendSuccess = function (e, o) {
+ var t;
+ if ("string" == typeof o) try {
+ t = JSON.parse(o)
+ } catch (e) {
+ (t = {}).data = o
+ } else "object" == typeof o ? t = o : (t = {}).data = o;
+ (Array.isArray(t) || "string" == typeof t) && (t = {
+ data: t,
+ code: 0
+ }), t.code ? t.code = 0 : (t.status, t.status = 0), t.__sekiro_seq__ = e;
+ var n = JSON.stringify(t);
+ console.log("response :" + n), this.socket.send(n)
+}, SekiroClient.prototype.sendFailed = function (e, o) {
+ "string" != typeof o && (o = JSON.stringify(o));
+ var t = {};
+ t.message = o, t.status = -1, t.__sekiro_seq__ = e;
+ var n = JSON.stringify(t);
+ console.log("sekiro: response :" + n), this.socket.send(n)
+}, SekiroClient.prototype.registerAction = function (e, o) {
+ if ("string" != typeof e) throw new Error("an action must be string");
+ if ("function" != typeof o) throw new Error("a handler must be function");
+ return console.log("sekiro: register action: " + e), this.handlers[e] = o, this
+};
+
+
+var client = new SekiroClient("ws://127.0.0.1:5612/business/register?group=ayf-ws&clientId=" + Math.random());
+client.registerAction("clientTime", function (request, resolve, reject) {
+ resolve("" + new Date());
+});
\ No newline at end of file