pluginloader:簡化go語言plugin函數(shù)和對象調(diào)用

2019-5-11 新增:

UnknownObject 類型增加了兩個(gè)新方法:JsonCopyToStruct玛歌,前一個(gè)導(dǎo)出JSON庄敛,后一個(gè)把結(jié)構(gòu)體的可導(dǎo)出值復(fù)制到另一個(gè)相似的結(jié)構(gòu)體中之碗。

2019-4-19 新修改:

  • 修改 pluginwrap ,刪除生成的文件中的 InitxxxFuncs,改為:func GetxxxFuncs(p *pluginloader.PluginLoader) *xxxFuncs低匙, 函數(shù)都被包含在 xxxFuncs結(jié)構(gòu)體中避免命名沖突漫拭。
  • pluginloader新增用于調(diào)用未定義結(jié)構(gòu)體的對象:UnknownObject。

2019-4-18 新修改:pluginwrap幾乎已經(jīng)完美了下翎! 現(xiàn)在除了用戶自定義類型缤言,已經(jīng)可以使用所有被導(dǎo)入庫的類型。

go語言的plugin調(diào)用還是很繁瑣视事,而且功能限制也不少胆萧,我開發(fā)了的這個(gè)程序包含一個(gè)包github.com/rocket049/pluginloader和一個(gè)命令行工具github.com/rocket049/pluginloader/cmd/pluginwrap

github.com/rocket049/pluginloader引用到程序中郑口,用于簡化函數(shù)調(diào)用鸳碧。

命令行工具pluginwrap用于從plugin的源代碼生成可導(dǎo)出對象struct對應(yīng)的interface和可導(dǎo)出func

使用pluginloader

安裝命令: go get github.com/rocket049/pluginloader

可調(diào)用的函數(shù):

type PluginLoader struct {
    P *plugin.Plugin
}

///Call return type must be: (res,error)
func (p *PluginLoader) Call(funcName string, p0 ...interface{}) (interface{}, error)

//CallValue Allow any number of return values,return type: []reflect.Value,error
func (p *PluginLoader) CallValue(funcName string, p0 ...interface{}) ([]reflect.Value, error)

//MakeFunc point a func ptr to plugin
func (s *PluginLoader) MakeFunc(fptr interface{}, name string) error 

//20190419 新增
//UnknownObject 成員'V' 必須是結(jié)構(gòu)體指針的 Value: *struct{...}
type UnknownObject struct {
    V reflect.Value
}
//NewUnknownObject 參數(shù)'v' 必須是結(jié)構(gòu)體指針的 Value: *struct{...}犬性,否則返回 nil
func NewUnknownObject(v reflect.Value) *UnknownObject 

//Get 得到結(jié)構(gòu)體成員的 Value
func (s *UnknownObject) Get(name string) reflect.Value

//Call 運(yùn)行結(jié)構(gòu)體的 method
func (s *UnknownObject) Call(fn string, args ...interface{}) []reflect.Value

//Json 把結(jié)構(gòu)體編碼為 JSON瞻离。 convert the struct to JSON. if error,return nil.
func (s *UnknownObject) Json() []byte 

//CopyToStruct 利用 reflect 技術(shù)把結(jié)構(gòu)體的可 export 值復(fù)制到 v 中,v 必須是相似結(jié)構(gòu)體的指針乒裆。 copy the exported value of a struct to v 
func (s *UnknownObject) CopyToStruct(v interface{}) error 

pluginloader導(dǎo)出method的具體說明

  • Call套利,直接通過函數(shù)名調(diào)用對應(yīng)的函數(shù),但是返回值形式受到限制鹤耍。
  • CallValue肉迫,直接通過函數(shù)名調(diào)用對應(yīng)的函數(shù),返回值形式不受限制稿黄。
  • MakeFunc喊衫,根據(jù)名字把預(yù)定義的函數(shù)類型變量指向插件中的函數(shù)。

UnknownObject說明

  • func NewUnknownObject(v reflect.Value) *UnknownObject杆怕,參數(shù)'v' 必須是結(jié)構(gòu)體指針的 Value: *struct{...}族购,否則返回 nil
  • Method:Get(name string) reflect.Value壳贪,得到結(jié)構(gòu)體成員的 Value
  • Method:Call(fn string, args ...interface{}) []reflect.Value,運(yùn)行結(jié)構(gòu)體的 method

調(diào)用示例

import "github.com/rocket049/pluginloader"

p, err := pluginloader.NewPluginLoader( "foo.so" )
if err != nil {
    panic(err)
}

res, err := p.Call("NameOfFunc", p0,p1,p3,...)
// ...

ret := p.CallValue("NameOfFunc", p0,p1,p3,...)
// ...

var Foo func(arg string)(string,error)
p.MakeFunc(&Foo,"Foo")
ret, err = Foo("something")
// ...

// 使用 UnknownObject. NewFoo return 'foo *Foo'
v, err := p.CallValue("NewFoo")
if err != nil {
    t.Fatal(err)
}
obj := NewUnknownObject(v[0])

id: = obj.Get("Id").Int()

err = obj.Call("Set", nil)

使用pluginwrap

安裝命令: go get github.com/rocket049/pluginloader/cmd/pluginwrap

用法

pluginwrap path/to/plugin/foo

生成的文件名字:
fooWrap.go

把這個(gè)文件加入你的工程就可以方便的調(diào)用plugin的導(dǎo)出函數(shù)了寝杖。

功能

  1. 生成導(dǎo)出對象的接口违施,以便用于類型斷言。
  2. 生成導(dǎo)出函數(shù)瑟幕。

限制

本程序基于標(biāo)準(zhǔn)包pluginreflect實(shí)現(xiàn)磕蒲,因?yàn)?code>go語言的變量類型轉(zhuǎn)換的使用有很多限制,所以本程序?qū)?dǎo)出函數(shù)的參數(shù)類型只盹、返回值類型都有限制辣往, 導(dǎo)出參數(shù)、返回值的類型僅限于基本類型鹿霸、標(biāo)準(zhǔn)庫排吴、第三方庫中的類型,不能使用自定義類型懦鼠。

如果必須使用自定義類型钻哩,有兩種辦法:

  1. 請使用 pluginloader.Callpluginloader.CallValue 調(diào)用。
  2. 把需要導(dǎo)出的復(fù)雜類型做成第三方庫(import "your/package")肛冶,不要在plugin源代碼中定義街氢。

示例

使用對象(struct)

    p, err := pluginloader.NewPluginLoader("foo.so")
    if err != nil {
        panic(err)
    }
    iface, err := p.Call("NewFoo",arg...)
    if err != nil {
        panic(err)
    }
    foo := iface.(IFoo)
    // use foo.Method

使用func

    //2090419 new
    p, err := pluginloader.NewPluginLoader("foo.so")
    if err != nil {
        panic(err)
    }
    
    // MUST call GetxxxFuncs(p) before call funcs, xxx = plugin名字
    funcs := GetfooFuncs(p)
    
    // call methods in plugin foo
    funcs.Method(arg)
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市睦袖,隨后出現(xiàn)的幾起案子珊肃,更是在濱河造成了極大的恐慌,老刑警劉巖馅笙,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伦乔,死亡現(xiàn)場離奇詭異,居然都是意外死亡董习,警方通過查閱死者的電腦和手機(jī)烈和,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來皿淋,“玉大人招刹,你說我怎么就攤上這事∥讶ぃ” “怎么了疯暑?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哑舒。 經(jīng)常有香客問我妇拯,道長,這世上最難降的妖魔是什么洗鸵? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任乖阵,我火速辦了婚禮宣赔,結(jié)果婚禮上预麸,老公的妹妹穿的比我還像新娘瞪浸。我一直安慰自己,他們只是感情好吏祸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布对蒲。 她就那樣靜靜地躺著,像睡著了一般贡翘。 火紅的嫁衣襯著肌膚如雪蹈矮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天鸣驱,我揣著相機(jī)與錄音泛鸟,去河邊找鬼。 笑死踊东,一個(gè)胖子當(dāng)著我的面吹牛北滥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闸翅,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼再芋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了坚冀?” 一聲冷哼從身側(cè)響起济赎,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎记某,沒想到半個(gè)月后司训,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡液南,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年壳猜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贺拣。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蓖谢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出譬涡,到底是詐尸還是另有隱情闪幽,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布涡匀,位于F島的核電站盯腌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏陨瘩。R本人自食惡果不足惜腕够,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一级乍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧帚湘,春花似錦玫荣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至资柔,卻和暖如春焙贷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贿堰。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工辙芍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人羹与。 一個(gè)月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓故硅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親注簿。 傳聞我的和親對象是個(gè)殘疾皇子契吉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容