Haxe / hscript - 防止将某些方法暴露给脚本
Haxe / hscript - Prevent exposing certain methods to scripts
所以,我创建了 "interface class" 和所有静态方法,我想将其公开给 hscript
脚本。它看起来像这样:
package com.application.interfaces.Terrain;
import com.application.TerrainCore
class Terrain {
private static var terrain:TerrainCore;
public static function _init(inTerrain:TerrainCore):Void {
terrain = inTerrain;
}
public static function test(s:Int):Void {
terrain.test(s);
}
}
问题是,我需要以某种方式设置 terrain
对象,但我不希望它暴露给脚本。我用
暴露整个 类
var interp = new Interp();
var module = Type.resolveClass("com.application.interfaces.Terrain");
interp.variables.set("Terrain", module)
我的想法是覆盖 hscript.Interp
中的方法 call
,这样它就不会执行任何名为 _init
的方法,但我不知道该怎么做。原始 call
方法如下所示:
function call( o : Dynamic, f : Dynamic, args : Array<Dynamic> ) : Dynamic {
return Reflect.callMethod(o,f,args);
}
您可以使用 Terrain 的 class 实例而不使用静态成员吗?例如:
interp.variables.set("Terrain", new Terrain(new TerrainCore()));
脚本用户不会知道他们使用的是静态方法还是实例方法,因为它仍然可以通过以下方式访问:
Terrain.test(123);
在脚本中。
另一种选择(基于 clemos)是使用 rtti 来计算允许的内容(而不是维护它的列表),例如:
Terrain._init(new TerrainCore());
_init 现在是一个私有函数,所以你需要从你的调用 class(见下文)中 @:allow
它,另外,你需要用 @:rtti
注释,这样你就可以在运行时获取有关函数的信息,因此 Terrain 现在看起来像:
@:rtti
class Terrain {
private static var terrain:TerrainCore;
@:allow(test.hscript.demo.Main)
private static function _init(inTerrain:TerrainCore):Void {
terrain = inTerrain;
}
public static function test(s:Int):Void {
terrain.test(s);
}
}
最后,脚本 interp fcall
现在支持字段是 public 还是私有,即:
public override function fcall(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic
var rtti = haxe.rtti.Rtti.getRtti(o);
for (field in rtti.statics) {
if (field.name == f && field.isPublic == false) {
error(EInvalidAccess(f));
}
}
return super.fcall(o, f, args);
}
值得注意的是,出于显而易见的原因,我使用了 statics
而不是 fields
。我也不确定这会对循环和 rtti 造成什么开销。
我认为您应该覆盖 fcall
,因为 call
仅用于顶层调用:
https://github.com/HaxeFoundation/hscript/blob/master/hscript/Interp.hx#L328-L331
过滤 f
参数应该很容易,例如:
if ( FORBIDDEN_FIELDS.indexOf( f ) > -1 ) throw EInvalidAccess( f );
或
if ( f.indexOf('_') == 0 ) throw EInvalidAccess( f );
所以,我创建了 "interface class" 和所有静态方法,我想将其公开给 hscript
脚本。它看起来像这样:
package com.application.interfaces.Terrain;
import com.application.TerrainCore
class Terrain {
private static var terrain:TerrainCore;
public static function _init(inTerrain:TerrainCore):Void {
terrain = inTerrain;
}
public static function test(s:Int):Void {
terrain.test(s);
}
}
问题是,我需要以某种方式设置 terrain
对象,但我不希望它暴露给脚本。我用
var interp = new Interp();
var module = Type.resolveClass("com.application.interfaces.Terrain");
interp.variables.set("Terrain", module)
我的想法是覆盖 hscript.Interp
中的方法 call
,这样它就不会执行任何名为 _init
的方法,但我不知道该怎么做。原始 call
方法如下所示:
function call( o : Dynamic, f : Dynamic, args : Array<Dynamic> ) : Dynamic {
return Reflect.callMethod(o,f,args);
}
您可以使用 Terrain 的 class 实例而不使用静态成员吗?例如:
interp.variables.set("Terrain", new Terrain(new TerrainCore()));
脚本用户不会知道他们使用的是静态方法还是实例方法,因为它仍然可以通过以下方式访问:
Terrain.test(123);
在脚本中。
另一种选择(基于 clemos)是使用 rtti 来计算允许的内容(而不是维护它的列表),例如:
Terrain._init(new TerrainCore());
_init 现在是一个私有函数,所以你需要从你的调用 class(见下文)中 @:allow
它,另外,你需要用 @:rtti
注释,这样你就可以在运行时获取有关函数的信息,因此 Terrain 现在看起来像:
@:rtti
class Terrain {
private static var terrain:TerrainCore;
@:allow(test.hscript.demo.Main)
private static function _init(inTerrain:TerrainCore):Void {
terrain = inTerrain;
}
public static function test(s:Int):Void {
terrain.test(s);
}
}
最后,脚本 interp fcall
现在支持字段是 public 还是私有,即:
public override function fcall(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic
var rtti = haxe.rtti.Rtti.getRtti(o);
for (field in rtti.statics) {
if (field.name == f && field.isPublic == false) {
error(EInvalidAccess(f));
}
}
return super.fcall(o, f, args);
}
值得注意的是,出于显而易见的原因,我使用了 statics
而不是 fields
。我也不确定这会对循环和 rtti 造成什么开销。
我认为您应该覆盖 fcall
,因为 call
仅用于顶层调用:
https://github.com/HaxeFoundation/hscript/blob/master/hscript/Interp.hx#L328-L331
过滤 f
参数应该很容易,例如:
if ( FORBIDDEN_FIELDS.indexOf( f ) > -1 ) throw EInvalidAccess( f );
或
if ( f.indexOf('_') == 0 ) throw EInvalidAccess( f );