sinkMeta.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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. Optional bool `json:"optional"`
  44. Type string `json:"type"`
  45. Hint *fileLanguage `json:"hint"`
  46. Label *fileLanguage `json:"label"`
  47. Values interface{} `json:"values"`
  48. }
  49. fileAbout struct {
  50. Trial bool `json:"trial"`
  51. Installed bool `json:"installed"`
  52. Author *author `json:"author"`
  53. HelpUrl *fileLanguage `json:"helpUrl"`
  54. Description *fileLanguage `json:"description"`
  55. }
  56. fileSink struct {
  57. About *fileAbout `json:"about"`
  58. Libs []string `json:"libs"`
  59. Fields []*fileField `json:"properties"`
  60. }
  61. language struct {
  62. English string `json:"en"`
  63. Chinese string `json:"zh"`
  64. }
  65. about struct {
  66. Trial bool `json:"trial"`
  67. Installed bool `json:"installed"`
  68. Author *author `json:"author"`
  69. HelpUrl *language `json:"helpUrl"`
  70. Description *language `json:"description"`
  71. }
  72. field struct {
  73. Exist bool `json:"exist"`
  74. Name string `json:"name"`
  75. Default interface{} `json:"default"`
  76. Type string `json:"type"`
  77. Control string `json:"control"`
  78. Optional bool `json:"optional"`
  79. Values interface{} `json:"values"`
  80. Hint *language `json:"hint"`
  81. Label *language `json:"label"`
  82. }
  83. uiSink struct {
  84. About *about `json:"about"`
  85. Libs []string `json:"libs"`
  86. Fields []field `json:"properties"`
  87. }
  88. )
  89. func newLanguage(fi *fileLanguage) *language {
  90. if nil == fi {
  91. return nil
  92. }
  93. ui := new(language)
  94. ui.English = fi.English
  95. ui.Chinese = fi.Chinese
  96. return ui
  97. }
  98. func newField(fis []*fileField) (uis []field, err error) {
  99. for _, fi := range fis {
  100. if nil == fi {
  101. continue
  102. }
  103. ui := field{
  104. Name: fi.Name,
  105. Type: fi.Type,
  106. Control: fi.Control,
  107. Optional: fi.Optional,
  108. Values: fi.Values,
  109. Hint: newLanguage(fi.Hint),
  110. Label: newLanguage(fi.Label),
  111. }
  112. uis = append(uis, ui)
  113. switch t := fi.Default.(type) {
  114. case []map[string]interface{}:
  115. var auxFi []*fileField
  116. if err = cast.MapToStruct(t, &auxFi); nil != err {
  117. return nil, err
  118. }
  119. if ui.Default, err = newField(auxFi); nil != err {
  120. return nil, err
  121. }
  122. default:
  123. ui.Default = fi.Default
  124. }
  125. }
  126. return uis, err
  127. }
  128. func newAbout(fi *fileAbout) *about {
  129. if nil == fi {
  130. return nil
  131. }
  132. ui := new(about)
  133. ui.Trial = fi.Trial
  134. ui.Installed = fi.Installed
  135. ui.Author = fi.Author
  136. ui.HelpUrl = newLanguage(fi.HelpUrl)
  137. ui.Description = newLanguage(fi.Description)
  138. return ui
  139. }
  140. func newUiSink(fi *fileSink) (*uiSink, error) {
  141. if nil == fi {
  142. return nil, nil
  143. }
  144. var err error
  145. ui := new(uiSink)
  146. ui.Libs = fi.Libs
  147. ui.About = newAbout(fi.About)
  148. ui.Fields, err = newField(fi.Fields)
  149. return ui, err
  150. }
  151. var gSinkmetadata = make(map[string]*uiSink) //immutable
  152. func ReadSinkMetaDir(checker InstallChecker) error {
  153. confDir, err := conf.GetConfLoc()
  154. if nil != err {
  155. return err
  156. }
  157. dir := path.Join(confDir, "sinks")
  158. files, err := ioutil.ReadDir(dir)
  159. if nil != err {
  160. return err
  161. }
  162. for _, file := range files {
  163. fname := file.Name()
  164. if !strings.HasSuffix(fname, ".json") {
  165. continue
  166. }
  167. filePath := path.Join(dir, fname)
  168. if err := ReadSinkMetaFile(filePath, checker(strings.TrimSuffix(fname, ".json"))); nil != err {
  169. return err
  170. }
  171. }
  172. return nil
  173. }
  174. func UninstallSink(name string) {
  175. if ui, ok := gSinkmetadata[name+".json"]; ok {
  176. if nil != ui.About {
  177. ui.About.Installed = false
  178. }
  179. }
  180. }
  181. func ReadSinkMetaFile(filePath string, installed bool) error {
  182. finame := path.Base(filePath)
  183. metadata := new(fileSink)
  184. err := filex.ReadJsonUnmarshal(filePath, metadata)
  185. if nil != err {
  186. return fmt.Errorf("filePath:%s err:%v", filePath, err)
  187. }
  188. if nil == metadata.About {
  189. return fmt.Errorf("not found about of %s", finame)
  190. } else {
  191. metadata.About.Installed = installed
  192. }
  193. gSinkmetadata[finame], err = newUiSink(metadata)
  194. if nil != err {
  195. return err
  196. }
  197. conf.Log.Infof("Loading metadata file for sink: %s", finame)
  198. return nil
  199. }
  200. func GetSinkMeta(pluginName, language string) (*uiSink, error) {
  201. fileName := pluginName + `.json`
  202. sinkMetadata := gSinkmetadata
  203. data, ok := sinkMetadata[fileName]
  204. if !ok || data == nil {
  205. return nil, fmt.Errorf(`%s%s`, getMsg(language, sink, "not_found_plugin"), pluginName)
  206. }
  207. return data, nil
  208. }
  209. type pluginfo struct {
  210. Name string `json:"name"`
  211. About *about `json:"about"`
  212. }
  213. func GetSinks() (sinks []*pluginfo) {
  214. sinkMeta := gSinkmetadata
  215. for fileName, v := range sinkMeta {
  216. node := new(pluginfo)
  217. node.Name = strings.TrimSuffix(fileName, `.json`)
  218. node.About = v.About
  219. i := 0
  220. for ; i < len(sinks); i++ {
  221. if node.Name <= sinks[i].Name {
  222. sinks = append(sinks, node)
  223. copy(sinks[i+1:], sinks[i:])
  224. sinks[i] = node
  225. break
  226. }
  227. }
  228. if len(sinks) == i {
  229. sinks = append(sinks, node)
  230. }
  231. }
  232. return sinks
  233. }