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.

230 lines
4.5 KiB

3 months ago
3 months ago
3 years ago
3 months ago
3 months ago
3 years ago
  1. package persistence
  2. import (
  3. "github.com/pkg/errors"
  4. "io/ioutil"
  5. "time"
  6. "dev.narayana.im/narayana/telegabber/yamldb"
  7. log "github.com/sirupsen/logrus"
  8. "gopkg.in/yaml.v2"
  9. )
  10. var zeroLocation *time.Location
  11. func init() {
  12. var err error
  13. zeroLocation, err = time.LoadLocation("")
  14. if err != nil {
  15. log.Fatal("Wrong hardcoded timezone")
  16. }
  17. }
  18. // SessionsYamlDB wraps YamlDB with Session
  19. type SessionsYamlDB struct {
  20. yamldb.YamlDB
  21. Data *SessionsMap
  22. }
  23. // SessionsMap is for :sessions: subtree
  24. type SessionsMap struct {
  25. Sessions map[string]Session `yaml:":sessions"`
  26. }
  27. // Session is a key-values subtree
  28. type Session struct {
  29. Login string `yaml:":login"`
  30. Timezone string `yaml:":timezone"`
  31. KeepOnline bool `yaml:":keeponline"`
  32. RawMessages bool `yaml:":rawmessages"`
  33. AsciiArrows bool `yaml:":asciiarrows"`
  34. OOBMode bool `yaml:":oobmode"`
  35. Carbons bool `yaml:":carbons"`
  36. HideIds bool `yaml:":hideids"`
  37. }
  38. var configKeys = []string{
  39. "timezone",
  40. "keeponline",
  41. "rawmessages",
  42. "asciiarrows",
  43. "oobmode",
  44. "carbons",
  45. "hideids",
  46. }
  47. var sessionDB *SessionsYamlDB
  48. // SessionMarshaller implementation for YamlDB
  49. func SessionMarshaller() ([]byte, error) {
  50. cleanedMap := SessionsMap{}
  51. emptySessionsMap(&cleanedMap)
  52. for jid, session := range sessionDB.Data.Sessions {
  53. if session.Login != "" {
  54. cleanedMap.Sessions[jid] = session
  55. }
  56. }
  57. return yaml.Marshal(&cleanedMap)
  58. }
  59. // LoadSessions restores TDlib sessions from the previous run
  60. func LoadSessions(path string) (*SessionsYamlDB, error) {
  61. var sessionData SessionsMap
  62. var err error
  63. sessionDB, err = initYamlDB(path, &sessionData)
  64. if err != nil {
  65. return sessionDB, errors.Wrap(err, "Sessions restore error")
  66. }
  67. return sessionDB, nil
  68. }
  69. func emptySessionsMap(dataPtr *SessionsMap) {
  70. dataPtr.Sessions = make(map[string]Session)
  71. }
  72. func initYamlDB(path string, dataPtr *SessionsMap) (*SessionsYamlDB, error) {
  73. file, err := ioutil.ReadFile(path)
  74. if err == nil {
  75. err = yaml.Unmarshal(file, dataPtr)
  76. if err != nil {
  77. return nil, errors.Wrap(err, "YamlDB is corrupted")
  78. }
  79. if dataPtr.Sessions == nil {
  80. emptySessionsMap(dataPtr)
  81. }
  82. log.Debugf("Unmarshalled YAML: %#v", *dataPtr)
  83. } else {
  84. // DB file does not exist, create an empty DB
  85. emptySessionsMap(dataPtr)
  86. }
  87. return &SessionsYamlDB{
  88. YamlDB: yamldb.YamlDB{
  89. Path: path,
  90. PathNew: path + ".new",
  91. },
  92. Data: dataPtr,
  93. }, nil
  94. }
  95. // Get retrieves a session value
  96. func (s *Session) Get(key string) (string, error) {
  97. switch key {
  98. case "timezone":
  99. return s.Timezone, nil
  100. case "keeponline":
  101. return fromBool(s.KeepOnline), nil
  102. case "rawmessages":
  103. return fromBool(s.RawMessages), nil
  104. case "asciiarrows":
  105. return fromBool(s.AsciiArrows), nil
  106. case "oobmode":
  107. return fromBool(s.OOBMode), nil
  108. case "carbons":
  109. return fromBool(s.Carbons), nil
  110. case "hideids":
  111. return fromBool(s.HideIds), nil
  112. }
  113. return "", errors.New("Unknown session property")
  114. }
  115. // ToMap converts the session to a map
  116. func (s *Session) ToMap() map[string]string {
  117. m := make(map[string]string)
  118. for _, configKey := range configKeys {
  119. value, _ := s.Get(configKey)
  120. m[configKey] = value
  121. }
  122. return m
  123. }
  124. // Set sets a session value
  125. func (s *Session) Set(key string, value string) (string, error) {
  126. switch key {
  127. case "timezone":
  128. s.Timezone = value
  129. return value, nil
  130. case "keeponline":
  131. b, err := toBool(value)
  132. if err != nil {
  133. return "", err
  134. }
  135. s.KeepOnline = b
  136. return value, nil
  137. case "rawmessages":
  138. b, err := toBool(value)
  139. if err != nil {
  140. return "", err
  141. }
  142. s.RawMessages = b
  143. return value, nil
  144. case "asciiarrows":
  145. b, err := toBool(value)
  146. if err != nil {
  147. return "", err
  148. }
  149. s.AsciiArrows = b
  150. return value, nil
  151. case "oobmode":
  152. b, err := toBool(value)
  153. if err != nil {
  154. return "", err
  155. }
  156. s.OOBMode = b
  157. return value, nil
  158. case "carbons":
  159. b, err := toBool(value)
  160. if err != nil {
  161. return "", err
  162. }
  163. s.Carbons = b
  164. return value, nil
  165. case "hideids":
  166. b, err := toBool(value)
  167. if err != nil {
  168. return "", err
  169. }
  170. s.HideIds = b
  171. return value, nil
  172. }
  173. return "", errors.New("Unknown session property")
  174. }
  175. // TimezoneToLocation tries to convert config timezone to location
  176. func (s *Session) TimezoneToLocation() *time.Location {
  177. time, err := time.Parse("-07:00", s.Timezone)
  178. if err == nil {
  179. return time.Location()
  180. }
  181. // default
  182. return zeroLocation
  183. }
  184. func fromBool(b bool) string {
  185. if b {
  186. return "true"
  187. } else {
  188. return "false"
  189. }
  190. }
  191. func toBool(s string) (bool, error) {
  192. switch s {
  193. case "true":
  194. return true, nil
  195. case "false":
  196. return false, nil
  197. }
  198. return false, errors.New("Invalid boolean value")
  199. }