new version update
Recently GScript
updated v0.0.11
version, focusing on updating:
Docker
Operating environment- Added byte primitive type
- Added some strings to the standard library
Strings/StringBuilder
- Array slice syntax:
int[] b = a[1: len(a)];
Please see below for specific updates.
foreword
posted online some time GScript
ago playground
,
This is a website that can run GScript
scripts . Its essential principle is to receive the user's input source code to run a service on the server; this is simply a backdoor open XSS
attack. In order to keep the server, I set the user rights API
of backend service. , which can avoid executing some malicious requests.
But it is unavoidable that some users perform some time-consuming operations, such as an infinite loop, demo
or printing the Yanghui triangle in the .
This is essentially a recursive function, which can be very time-consuming and CPU-intensive when the number of printed triangle layers is too high.
A few times when I went to check the server, I found several processes with too high CPU. Basically, it is such a time-consuming operation, which will inevitably affect the performance of the server.
Use Docker
In order to solve this kind of problem, it is natural to think that it can be used Docker
. All resources are isolated from the host, and no matter how much you mess around, it will not affect the host.
Just do it, and finally modify the place where the API executes the script:
string fileName = d.unix("Asia/Shanghai") + "temp.gs" ;
s.writeFile(fileName, body, 438);
string pwd = s.getwd();
// string res = s.command("gscript", fileName);
string res = s.command("docker","run","--rm","-v", pwd+":/usr/src/gscript","-w","/usr/src/gscript", "crossoverjie/gscript","gscript", fileName);
s.remove(fileName);
r.body = res;
r.ast = dumpAST(body);
r.symbol=dumpSymbol(body);
ctx.JSON(200, r);
复制代码
The main modification is to change the directly executed GScript
command to call docker
execution.
But in fact, there is still room for improvement. After adding a new coroutine, you can monitor the running time, and automatically kill the process after the timeout.
I also Docker
uploaded it, and now everyone just needs to run it when DockerHub
they want to experience GScript
it .REPL
Docker
docker pull crossoverjie/gscript
docker run --rm -it crossoverjie/gscript:latest gscript
复制代码
当然也可以执行用 Docker
执行 GScript
脚本:
docker run --rm -v $PWD:/usr/src/gscript -w /usr/src/gscript crossoverjie/gscript gscript {yourpath}/temp.gs
复制代码
编写 GScript 标准库
接下来重点聊聊 GScript
标准库的事情,其实编写标准库是一个费时费力的事情。 现在编译器已经提供了一些可用的内置函数,借由这些内置函数写一些常见的工具类是完全没有问题的。
对写 GScript
标准库感谢的朋友可以当做一个参考,这里我打了一个样,先看下运行效果:
// 字符串工具类
StringBuilder b = StringBuilder();
b.writeString("10");
b.writeString("20");
int l = b.writeString("30");
string s = b.String();
printf("s:%s, len=%d ",s,l);
assertEqual(s,"102030");
byte[] b2 = toByteArray("40");
b.WriteBytes(b2);
s = b.String();
assertEqual(s,"10203040");
println(s);
// Strings 工具类
Strings s = Strings();
string[] elems = {"name=xxx","age=xx"};
string ret = s.join(elems, "&");
println(ret);
assertEqual(ret, "name=xxx&age=xx");
bool b = s.hasPrefix("http://www.xx.com", "http");
println(b);
assertEqual(b,true);
b = s.hasPrefix("http://www.xx.com", "https");
println(b);
assertEqual(b,false);
复制代码
其中的实现源码基本上是借鉴了 Go 的标准库,先来看看 StringBuilder
的源码:
class StringBuilder{
byte[] buf = [0]{};
// append contents to buf, it returns the length of s
int writeString(string s){
byte[] temp = toByteArray(s);
append(buf, temp);
return len(temp);
}
// append b to buf, it returns the length of b.
int WriteBytes(byte[] b){
append(buf, b);
return len(b);
}
// copies the buffer to a new.
grow(int n){
if (n > 0) {
// when there is not enough space left.
if (cap(buf) - len(buf) < n) {
byte[] newBuf = [len(buf), 2*cap(buf)+n]{};
copy(newBuf, buf);
buf = newBuf;
}
}
}
string String(){
return toString(buf);
}
}
复制代码
主要就是借助了原始的数组类型以及 toByteArray/toString
字节数组和字符串的转换函数实现的。
class Strings{
// concatenates the elements of its first argument to create a single string. The separator
// string sep is placed between elements in the resulting string.
string join(string[] elems, string sep){
if (len(elems) == 0) {
return "";
}
if (len(elems) == 1) {
return elems[0];
}
byte[] bs = toByteArray(sep);
int n = len(bs) * (len(elems) -1);
for (int i=0; i < len(elems); i++) {
string s = elems[i];
byte[] bs = toByteArray(s);
n = n + len(bs);
}
StringBuilder sb = StringBuilder();
sb.grow(n);
string first = elems[0];
sb.writeString(first);
string[] remain = elems[1:len(elems)];
for(int i=0; i < len(remain); i++){
sb.writeString(sep);
string r = remain[i];
sb.writeString(r);
}
return sb.String();
}
// tests whether the string s begins with prefix.
bool hasPrefix(string s, string prefix){
byte[] bs = toByteArray(s);
byte[] bp = toByteArray(prefix);
return len(bs) >= len(bp) && toString(bs[0:len(bp)]) == prefix;
}
}
复制代码
Strings
工具类也是类似的,都是一些内置函数的组合运用;
在写标准库的过程中还会有额外收获,可以再次阅读一遍 Go 标准库的实现流程,换了一种语法实现出来,会加深对 Go 标准库的理解。
所以欢迎感兴趣的朋友向 GScript
贡献标准库,由于我个人精力有限,实现过程中可能会发现缺少某些内置函数或数据结构,这也没关系,反馈 issue
后我会尽快处理。
由于目前
GScript
还不支持包管理,所以新增的函数可以创建Class
来实现,后续支持包或者是namespace
之后直接将该Class
迁移过去即可。
本文相关资源链接
- GScript 源码:github.com/crossoverJi…
- Playground 源码:github.com/crossoverJi…
- GScript Docker地址:hub.docker.com/r/crossover…