sinkMeta.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // Copyright 2021 EMQ Technologies Co., Ltd.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package meta
  15. import (
  16. "fmt"
  17. "github.com/lf-edge/ekuiper/internal/conf"
  18. "github.com/lf-edge/ekuiper/internal/pkg/filex"
  19. "github.com/lf-edge/ekuiper/pkg/cast"
  20. "io/ioutil"
  21. "path"
  22. "strings"
  23. )
  24. const (
  25. sink = `sink`
  26. source = `source`
  27. )
  28. type (
  29. author struct {
  30. Name string `json:"name"`
  31. Email string `json:"email"`
  32. Company string `json:"company"`
  33. Website string `json:"website"`
  34. }
  35. fileLanguage struct {
  36. English string `json:"en_US"`
  37. Chinese string `json:"zh_CN"`
  38. }
  39. fileField struct {
  40. Name string `json:"name"`
  41. Default interface{} `json:"default"`
  42. Control string `json:"control"`
  43. ConnectionRelated bool `json:"connection_related"`
  44. Optional bool `json:"optional"`
  45. Type string `json:"type"`
  46. Hint *fileLanguage `json:"hint"`
  47. Label *fileLanguage `json:"label"`
  48. Values interface{} `json:"values"`
  49. }
  50. fileAbout struct {
  51. Trial bool `json:"trial"`
  52. Installed bool `json:"installed"`
  53. Author *author `json:"author"`
  54. HelpUrl *fileLanguage `json:"helpUrl"`
  55. Description *fileLanguage `json:"description"`
  56. }
  57. fileSink struct {
  58. About *fileAbout `json:"about"`
  59. Libs []string `json:"libs"`
  60. Fields []*fileField `json:"properties"`
  61. }
  62. language struct {
  63. English string `json:"en"`
  64. Chinese string `json:"zh"`
  65. }
  66. about struct {
  67. Trial bool `json:"trial"`
  68. Installed bool `json:"installed"`
  69. Author *author `json:"author"`
  70. HelpUrl *language `json:"helpUrl"`
  71. Description *language `json:"description"`
  72. }
  73. field struct {
  74. Exist bool `json:"exist"`
  75. Name string `json:"name"`
  76. Default interface{} `json:"default"`
  77. Type string `json:"type"`
  78. Control string `json:"control"`
  79. ConnectionRelated bool `json:"connection_related"`
  80. Optional bool `json:"optional"`
  81. Values interface{} `json:"values"`
  82. Hint *language `json:"hint"`
  83. Label *language `json:"label"`
  84. }
  85. uiSink struct {
  86. About *about `json:"about"`
  87. Libs []string `json:"libs"`
  88. Fields []field `json:"properties"`
  89. }
  90. )
  91. func newLanguage(fi *fileLanguage) *language {
  92. if nil == fi {
  93. return nil
  94. }
  95. ui := new(language)
  96. ui.English = fi.English
  97. ui.Chinese = fi.Chinese
  98. return ui
  99. }
  100. func newField(fis []*fileField) (uis []field, err error) {
  101. for _, fi := range fis {
  102. if nil == fi {
  103. continue
  104. }
  105. ui := field{
  106. Name: fi.Name,
  107. Type: fi.Type,
  108. Control: fi.Control,
  109. ConnectionRelated: fi.ConnectionRelated,
  110. Optional: fi.Optional,
  111. Values: fi.Values,
  112. Hint: newLanguage(fi.Hint),
  113. Label: newLanguage(fi.Label),
  114. }
  115. uis = append(uis, ui)
  116. switch t := fi.Default.(type) {
  117. case []map[string]interface{}:
  118. var auxFi []*fileField
  119. if err = cast.MapToStruct(t, &auxFi); nil != err {
  120. return nil, err
  121. }
  122. if ui.Default, err = newField(auxFi); nil != err {
  123. return nil, err
  124. }
  125. default:
  126. ui.Default = fi.Default
  127. }
  128. }
  129. return uis, err
  130. }
  131. func newAbout(fi *fileAbout) *about {
  132. if nil == fi {
  133. return nil
  134. }
  135. ui := new(about)
  136. ui.Trial = fi.Trial
  137. ui.Installed = fi.Installed
  138. ui.Author = fi.Author
  139. ui.HelpUrl = newLanguage(fi.HelpUrl)
  140. ui.Description = newLanguage(fi.Description)
  141. return ui
  142. }
  143. func newUiSink(fi *fileSink) (*uiSink, error) {
  144. if nil == fi {
  145. return nil, nil
  146. }
  147. var err error
  148. ui := new(uiSink)
  149. ui.Libs = fi.Libs
  150. ui.About = newAbout(fi.About)
  151. ui.Fields, err = newField(fi.Fields)
  152. return ui, err
  153. }
  154. var gSinkmetadata = make(map[string]*uiSink) //immutable
  155. func ReadSinkMetaDir(checker InstallChecker) error {
  156. confDir, err := conf.GetConfLoc()
  157. if nil != err {
  158. return err
  159. }
  160. dir := path.Join(confDir, "sinks")
  161. files, err := ioutil.ReadDir(dir)
  162. if nil != err {
  163. return err
  164. }
  165. for _, file := range files {
  166. fname := file.Name()
  167. if !strings.HasSuffix(fname, ".json") {
  168. continue
  169. }
  170. filePath := path.Join(dir, fname)
  171. if err := ReadSinkMetaFile(filePath, checker(strings.TrimSuffix(fname, ".json"))); nil != err {
  172. return err
  173. }
  174. }
  175. return nil
  176. }
  177. func UninstallSink(name string) {
  178. if ui, ok := gSinkmetadata[name+".json"]; ok {
  179. if nil != ui.About {
  180. ui.About.Installed = false
  181. }
  182. }
  183. }
  184. func ReadSinkMetaFile(filePath string, installed bool) error {
  185. finame := path.Base(filePath)
  186. metadata := new(fileSink)
  187. err := filex.ReadJsonUnmarshal(filePath, metadata)
  188. if nil != err {
  189. return fmt.Errorf("filePath:%s err:%v", filePath, err)
  190. }
  191. if nil == metadata.About {
  192. return fmt.Errorf("not found about of %s", finame)
  193. } else {
  194. metadata.About.Installed = installed
  195. }
  196. gSinkmetadata[finame], err = newUiSink(metadata)
  197. if nil != err {
  198. return err
  199. }
  200. conf.Log.Infof("Loading metadata file for sink: %s", finame)
  201. return nil
  202. }
  203. func GetSinkMeta(pluginName, language string) (*uiSink, error) {
  204. fileName := pluginName + `.json`
  205. sinkMetadata := gSinkmetadata
  206. data, ok := sinkMetadata[fileName]
  207. if !ok || data == nil {
  208. return nil, fmt.Errorf(`%s%s`, getMsg(language, sink, "not_found_plugin"), pluginName)
  209. }
  210. return data, nil
  211. }
  212. type pluginfo struct {
  213. Name string `json:"name"`
  214. About *about `json:"about"`
  215. }
  216. func GetSinks() (sinks []*pluginfo) {
  217. sinkMeta := gSinkmetadata
  218. for fileName, v := range sinkMeta {
  219. node := new(pluginfo)
  220. node.Name = strings.TrimSuffix(fileName, `.json`)
  221. node.About = v.About
  222. i := 0
  223. for ; i < len(sinks); i++ {
  224. if node.Name <= sinks[i].Name {
  225. sinks = append(sinks, node)
  226. copy(sinks[i+1:], sinks[i:])
  227. sinks[i] = node
  228. break
  229. }
  230. }
  231. if len(sinks) == i {
  232. sinks = append(sinks, node)
  233. }
  234. }
  235. return sinks
  236. }