You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
3.5 KiB

  1. package main
  2. import (
  3. "context"
  4. "git.aiterp.net/lucifer/new-server/app/client"
  5. "git.aiterp.net/lucifer/new-server/models"
  6. "gopkg.in/yaml.v2"
  7. "log"
  8. "os"
  9. "strconv"
  10. "strings"
  11. "unicode"
  12. )
  13. func sceneCmd(
  14. ctx context.Context,
  15. c client.Client,
  16. ) {
  17. cmd := parseCommand(os.Args[2:])
  18. switch cmd.Name {
  19. case "create", "update":
  20. {
  21. fileName := cmd.Params.Get(0).String()
  22. if fileName == nil {
  23. log.Fatalln("Missing filename")
  24. }
  25. file, err := os.Open(*fileName)
  26. if err != nil {
  27. log.Fatalln("Failed to open file:", err)
  28. }
  29. defer file.Close()
  30. yamlData := make(map[string]interface{})
  31. err = yaml.NewDecoder(file).Decode(yamlData)
  32. if err != nil {
  33. log.Fatalln("Failed to decode file:", err)
  34. return
  35. }
  36. yamlData = camelCasify(yamlData)
  37. name, nameOk := yamlData["name"]
  38. if !nameOk {
  39. log.Fatalln("Missing name in yaml data.")
  40. }
  41. var scene models.Scene
  42. if cmd.Name == "create" {
  43. err := c.Fetch(ctx, "POST", "/api/scenes", &scene, yamlData)
  44. if err != nil {
  45. log.Fatalln("Failed to create scene:", err)
  46. return
  47. }
  48. } else {
  49. scenes, err := c.GetScenes(ctx)
  50. if err != nil {
  51. log.Fatalln("Failed to fetch existing scenes:", err)
  52. return
  53. }
  54. id := -1
  55. for _, scene := range scenes {
  56. if scene.Name == name {
  57. id = scene.ID
  58. break
  59. }
  60. }
  61. if id == -1 {
  62. log.Fatalln("Could not find scene with name", name)
  63. return
  64. }
  65. err = c.Fetch(ctx, "PUT", "/api/scenes/"+strconv.Itoa(id), &scene, yamlData)
  66. if err != nil {
  67. log.Fatalln("Failed to update scene:", err)
  68. return
  69. }
  70. }
  71. }
  72. case "push", "assign":
  73. {
  74. fetch := cmd.Params.Get(0).String()
  75. id := cmd.Params.Get(1).Int()
  76. if fetch == nil || id == nil {
  77. log.Println("Usage: lucy scene assign <fetch> <id> <group=S> <duration=I>")
  78. }
  79. devices, err := c.AssignDevice(ctx, *fetch, cmd.Name == "push", models.DeviceSceneAssignment{
  80. SceneID: *id,
  81. Group: cmd.Params.Get("group").StringOr(*fetch),
  82. DurationMS: int64(cmd.Params.Get("duration").IntOr(0)),
  83. })
  84. if err != nil {
  85. log.Println("Could not assign devices:", err)
  86. return
  87. }
  88. WriteDeviceInfoTable(os.Stdout, devices)
  89. }
  90. case "clear":
  91. fetch := cmd.Params.Get(0).String()
  92. if fetch == nil {
  93. log.Println("Usage: lucy scene clear <fetch>")
  94. }
  95. devices, err := c.ClearDevice(ctx, *fetch)
  96. if err != nil {
  97. log.Println("Could not clear devices:", err)
  98. return
  99. }
  100. WriteDeviceInfoTable(os.Stdout, devices)
  101. }
  102. }
  103. func camelCasify(m map[string]interface{}) map[string]interface{} {
  104. m2 := make(map[string]interface{}, len(m))
  105. for key, value := range m {
  106. b := strings.Builder{}
  107. snake := false
  108. for _, ch := range key {
  109. if ch == '_' {
  110. snake = true
  111. } else if snake {
  112. b.WriteRune(unicode.ToUpper(ch))
  113. snake = false
  114. } else {
  115. b.WriteRune(ch)
  116. }
  117. }
  118. switch value := value.(type) {
  119. case []interface{}:
  120. valueCopy := make([]interface{}, len(value))
  121. for i, elem := range value {
  122. switch elem := elem.(type) {
  123. case map[interface{}]interface{}:
  124. m3 := make(map[string]interface{})
  125. for k, v := range elem {
  126. if kStr, ok := k.(string); ok {
  127. m3[kStr] = v
  128. }
  129. }
  130. valueCopy[i] = camelCasify(m3)
  131. case map[string]interface{}:
  132. valueCopy[i] = camelCasify(elem)
  133. default:
  134. valueCopy[i] = elem
  135. }
  136. }
  137. m2[b.String()] = valueCopy
  138. case map[string]interface{}:
  139. m2[b.String()] = camelCasify(value)
  140. default:
  141. m2[b.String()] = value
  142. }
  143. }
  144. return m2
  145. }