Ei kuvausta

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. package funmow
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "github.com/boltdb/bolt"
  9. "regexp"
  10. "strconv"
  11. )
  12. const (
  13. DEBUG = false
  14. )
  15. type DBRef int
  16. func NewDBRefFromHashRef(v string) (DBRef, bool) {
  17. var destInt int
  18. if matched, _ := regexp.MatchString(`^\pZ*#[0-9]+\pZ*?`, v); !matched {
  19. return 0, false
  20. }
  21. n, err := fmt.Sscanf(v, "#%d", &destInt)
  22. if err != nil || n == 0 {
  23. return 0, false
  24. }
  25. return DBRef(destInt), true
  26. }
  27. func NewDBRefFromString(v string) (DBRef, error) {
  28. intVal, err := strconv.Atoi(v)
  29. return DBRef(intVal), err
  30. }
  31. func NewDBRefFromKey(b []byte) DBRef {
  32. return DBRef(binary.BigEndian.Uint64(b))
  33. }
  34. func NewDBRefFromChildKey(b []byte) DBRef { // returns the child part of a childkey
  35. return DBRef(binary.BigEndian.Uint64(b[8:]))
  36. }
  37. func (r DBRef) Valid() bool {
  38. return r != 0
  39. }
  40. func (r DBRef) Limbo() bool {
  41. return r == 0
  42. }
  43. func (r DBRef) String() string {
  44. return strconv.Itoa(int(r))
  45. }
  46. func (r DBRef) Key() []byte {
  47. b := make([]byte, 8)
  48. binary.BigEndian.PutUint64(b, uint64(r))
  49. return b
  50. }
  51. func (r DBRef) ChildKey(s DBRef) []byte {
  52. b := make([]byte, 16)
  53. binary.BigEndian.PutUint64(b, uint64(r))
  54. binary.BigEndian.PutUint64(b[8:], uint64(s))
  55. return b
  56. }
  57. type DBRefList []DBRef
  58. func (l DBRefList) First() DBRef {
  59. if len(l) > 0 {
  60. return l[0]
  61. } else {
  62. return 0
  63. }
  64. }
  65. type DB struct {
  66. path string
  67. db *bolt.DB
  68. }
  69. func NewDB(path string) *DB {
  70. return &DB{path: path}
  71. }
  72. func (s *DB) Close() {
  73. s.db.Close()
  74. }
  75. func (s *DB) Open() error {
  76. var err error
  77. s.db, err = bolt.Open(s.path, 0600, nil)
  78. if err != nil {
  79. return err
  80. }
  81. return s.db.Update(func(tx *bolt.Tx) error {
  82. var err error
  83. _, err = tx.CreateBucketIfNotExists([]byte("object"))
  84. if err != nil {
  85. return fmt.Errorf("create bucket: %s", err)
  86. }
  87. _, err = tx.CreateBucketIfNotExists([]byte("child"))
  88. if err != nil {
  89. return fmt.Errorf("create bucket: %s", err)
  90. }
  91. _, err = tx.CreateBucketIfNotExists([]byte("parent"))
  92. if err != nil {
  93. return fmt.Errorf("create bucket: %s", err)
  94. }
  95. _, err = tx.CreateBucketIfNotExists([]byte("player"))
  96. if err != nil {
  97. return fmt.Errorf("create bucket: %s", err)
  98. }
  99. return nil
  100. })
  101. }
  102. func (s *DB) Allocate() (DBRef, error) {
  103. var id DBRef
  104. err := s.db.Update(func(tx *bolt.Tx) error {
  105. b := tx.Bucket([]byte("object"))
  106. seq, err := b.NextSequence()
  107. if err != nil {
  108. return err
  109. }
  110. id = DBRef(seq)
  111. return s.txStoreObject(b, Object{ID: id}, id)
  112. })
  113. return id, err
  114. }
  115. func (s *DB) Fetch(r DBRef) (Object, bool) { // this has become simply an alias for RetrieveObject
  116. return s.RetrieveObject(r)
  117. }
  118. func (s *DB) DumpObject(r DBRef) string {
  119. var dump string
  120. s.db.View(func(tx *bolt.Tx) error {
  121. objectBucket := tx.Bucket([]byte("object"))
  122. childBucket := tx.Bucket([]byte("child"))
  123. parentBucket := tx.Bucket([]byte("parent"))
  124. objectDump := string(objectBucket.Get(r.Key()))
  125. intermediate := make([]string, 0)
  126. children := s.txGetChildren(childBucket, r)
  127. for childID, childType := range children {
  128. intermediate = append(intermediate, fmt.Sprintf("#%d (%s)", childID, childType))
  129. }
  130. parent, hasParent := s.txGetParent(parentBucket, r)
  131. dump = fmt.Sprintf("Object: %s\nHas Parent: %t\nParent ID: #%d\nChildren: %s", objectDump, hasParent, parent, intermediate)
  132. return nil
  133. })
  134. return dump
  135. }
  136. func (s *DB) Delete(objectID DBRef) error {
  137. return s.db.Update(func(tx *bolt.Tx) error {
  138. objectBucket := tx.Bucket([]byte("object"))
  139. childBucket := tx.Bucket([]byte("child"))
  140. parentBucket := tx.Bucket([]byte("parent"))
  141. _, found := s.txRetrieveObject(objectBucket, objectID)
  142. if !found {
  143. return nil
  144. }
  145. parentID, parentFound := s.txGetParent(parentBucket, objectID)
  146. if parentFound {
  147. //fmt.Printf("Unlinking from parent #%d\n", parentID)
  148. err := s.txUnlink(childBucket, parentBucket, parentID, objectID)
  149. if err != nil {
  150. return err
  151. }
  152. }
  153. children := s.txGetChildren(childBucket, objectID)
  154. for childID, childType := range children {
  155. //fmt.Printf("Unlinking child #%d\n",childID)
  156. err := s.txUnlink(childBucket, parentBucket, objectID, childID)
  157. if err != nil {
  158. return err
  159. }
  160. if childType == "exit" {
  161. //fmt.Printf("Deleting exit child #%d\n", childID)
  162. err := s.txDelete(objectBucket, childID) // this is bad and will create orphans
  163. if err != nil {
  164. return err
  165. }
  166. } else {
  167. // even if parentfound == false, parentID will = 0 (the default value for rooms)
  168. // that will cause the contents of destroyed rooms to end up in limbo, instead of as orpans
  169. //fmt.Printf("Linking child #%d to parent #%d\n",childID, parentID)
  170. err := s.txLink(childBucket, parentBucket, parentID, childID, childType)
  171. if err != nil {
  172. return err
  173. }
  174. }
  175. }
  176. //fmt.Printf("Deleting object #%d\n", objectID)
  177. err := s.txDelete(objectBucket, objectID)
  178. if err != nil {
  179. return err
  180. }
  181. if DEBUG {
  182. fmt.Printf("Delete name: id: %d\n", objectID)
  183. }
  184. return nil
  185. })
  186. }
  187. func (s *DB) SetPlayerPassword(name string, oldPassword string, newPassword string) bool {
  188. updated := false
  189. s.db.Update(func(tx *bolt.Tx) error {
  190. b := tx.Bucket([]byte("player"))
  191. v := b.Get([]byte(name))
  192. if v == nil {
  193. return fmt.Errorf("player doesn't exist")
  194. }
  195. var player PlayerMeta
  196. err := json.Unmarshal(v, &player)
  197. if err != nil {
  198. return err
  199. }
  200. if player.Password != oldPassword {
  201. return fmt.Errorf("password mismatch")
  202. }
  203. player.Password = newPassword
  204. buf, err := json.Marshal(player)
  205. if err != nil {
  206. return err
  207. }
  208. err = b.Put([]byte(name), buf)
  209. if err != nil {
  210. return err
  211. }
  212. updated = true
  213. return nil
  214. })
  215. return updated
  216. }
  217. func (s *DB) SetPlayer(name string, player PlayerMeta) error {
  218. err := s.db.Update(func(tx *bolt.Tx) error {
  219. buf, err := json.Marshal(player)
  220. if err != nil {
  221. return err
  222. }
  223. b := tx.Bucket([]byte("player"))
  224. return b.Put([]byte(name), buf)
  225. })
  226. return err
  227. }
  228. func (s *DB) GetPlayer(name string) (PlayerMeta, bool) {
  229. var player PlayerMeta
  230. found := false
  231. s.db.View(func(tx *bolt.Tx) error {
  232. b := tx.Bucket([]byte("player"))
  233. v := b.Get([]byte(name))
  234. if v == nil {
  235. return nil
  236. }
  237. err := json.Unmarshal(v, &player)
  238. if err == nil {
  239. found = true
  240. }
  241. return nil
  242. })
  243. return player, found
  244. }
  245. func (s *DB) DeletePlayer(name string) error {
  246. return s.db.Update(func(tx *bolt.Tx) error {
  247. playerBucket := tx.Bucket([]byte("player"))
  248. err := playerBucket.Delete([]byte(name))
  249. return err
  250. })
  251. }
  252. func (s *DB) RenamePlayer(oldName string, newName string) error {
  253. // doing it this way accomplishes the change as a single transasction
  254. // and saves a bunch of marshalling and unmarshalling
  255. return s.db.Update(func(tx *bolt.Tx) error {
  256. playerBucket := tx.Bucket([]byte("player"))
  257. buf := playerBucket.Get([]byte(oldName))
  258. if buf == nil {
  259. return errors.New("Can't find player")
  260. }
  261. err := playerBucket.Delete([]byte(oldName))
  262. if err != nil {
  263. return err
  264. }
  265. return playerBucket.Put([]byte(newName), buf)
  266. })
  267. }
  268. func (s *DB) CreatePlayer(name string, password string, flags map[string]bool) (DBRef, error) {
  269. var playerID DBRef
  270. err := s.db.Update(func(tx *bolt.Tx) error {
  271. objectBucket := tx.Bucket([]byte("object"))
  272. playerBucket := tx.Bucket([]byte("player"))
  273. seq, err := objectBucket.NextSequence()
  274. if err != nil {
  275. return err
  276. }
  277. playerID = DBRef(seq)
  278. s.txStoreObject(objectBucket, Object{ID: playerID, Name: name, Type: "player", Flags: flags}, playerID)
  279. playerMeta := PlayerMeta{ID: playerID, Password: password}
  280. buf, err := json.Marshal(playerMeta)
  281. if err != nil {
  282. return err
  283. }
  284. err = playerBucket.Put([]byte(name), buf)
  285. return err
  286. })
  287. if DEBUG {
  288. fmt.Printf("CreatePlayer name: %s id: %d\n", name, playerID)
  289. }
  290. return playerID, err
  291. }
  292. // All of these functions exist in two forms; one for use inside a transaction and one
  293. // for use outside a transaction.
  294. func (s *DB) RetrieveObject(id DBRef) (Object, bool) {
  295. o := Object{}
  296. f := false
  297. s.db.View(func(tx *bolt.Tx) error {
  298. b := tx.Bucket([]byte("object"))
  299. o, f = s.txRetrieveObject(b, id)
  300. return nil
  301. })
  302. return o, f
  303. }
  304. func (s *DB) txRetrieveObject(b *bolt.Bucket, id DBRef) (Object, bool) {
  305. o := Object{}
  306. f := false
  307. v := b.Get(id.Key())
  308. if v != nil {
  309. err := json.Unmarshal(v, &o)
  310. if err == nil {
  311. f = true
  312. if DEBUG {
  313. fmt.Printf("txRetrieveObject id: %d\n", id)
  314. }
  315. }
  316. }
  317. o.db = s // bit ugly but saves a lot of headaches
  318. return o, f
  319. }
  320. func (s *DB) StoreObject(o Object, id DBRef) error {
  321. return s.db.Update(func(tx *bolt.Tx) error {
  322. b := tx.Bucket([]byte("object"))
  323. return s.txStoreObject(b, o, id)
  324. })
  325. }
  326. func (s *DB) txStoreObject(b *bolt.Bucket, o Object, id DBRef) error {
  327. buf, err := json.Marshal(o)
  328. if err != nil {
  329. return err
  330. }
  331. err = b.Put(id.Key(), buf)
  332. if err != nil {
  333. return err
  334. }
  335. if DEBUG {
  336. fmt.Printf("txStoreObject id: %d\n", id)
  337. }
  338. return nil
  339. }
  340. func (s *DB) GetChildren(src DBRef) map[DBRef]string {
  341. var l map[DBRef]string
  342. s.db.View(func(tx *bolt.Tx) error {
  343. c := tx.Bucket([]byte("child"))
  344. l = s.txGetChildren(c, src)
  345. return nil
  346. })
  347. return l
  348. }
  349. func (s *DB) txGetChildren(b *bolt.Bucket, src DBRef) map[DBRef]string {
  350. l := make(map[DBRef]string)
  351. prefix := src.Key() // 00001234
  352. start := src.ChildKey(0) // 0000123400000000
  353. c := b.Cursor()
  354. for k, v := c.Seek(start); bytes.HasPrefix(k, prefix); k, v = c.Next() {
  355. l[NewDBRefFromChildKey(k)] = string(v)
  356. }
  357. return l
  358. }
  359. func (s *DB) GetParent(src DBRef) (DBRef, bool) {
  360. p := DBRef(0)
  361. f := false
  362. s.db.View(func(tx *bolt.Tx) error {
  363. parentBucket := tx.Bucket([]byte("parent"))
  364. p, f = s.txGetParent(parentBucket, src)
  365. return nil
  366. })
  367. return p, f
  368. }
  369. func (s *DB) txGetParent(parentBucket *bolt.Bucket, childID DBRef) (DBRef, bool) {
  370. parentID := DBRef(0)
  371. f := false
  372. v := parentBucket.Get(childID.Key())
  373. if v != nil {
  374. parentID = NewDBRefFromKey(v)
  375. f = true
  376. }
  377. if DEBUG {
  378. fmt.Printf("txGetParent child: %d parent: %d\n", childID, parentID)
  379. }
  380. //fmt.Printf("txGetParent src: %d found: %t parent: %d\n", src, f, p)
  381. return parentID, f
  382. }
  383. func (s *DB) IsParent(src DBRef, dest DBRef) bool {
  384. f := false
  385. s.db.View(func(tx *bolt.Tx) error {
  386. parentBucket := tx.Bucket([]byte("parent"))
  387. f = s.txIsParent(parentBucket, src, dest)
  388. return nil
  389. })
  390. return f
  391. }
  392. func (s *DB) txIsParent(b *bolt.Bucket, src DBRef, dst DBRef) bool {
  393. v := b.Get(src.Key())
  394. if v != nil {
  395. return (bytes.Compare(v, dst.Key()) == 0)
  396. }
  397. return false
  398. }
  399. func (s *DB) IsChild(src DBRef, dest DBRef) (string, bool) {
  400. t := ""
  401. f := false
  402. s.db.View(func(tx *bolt.Tx) error {
  403. childBucket := tx.Bucket([]byte("child"))
  404. t, f = s.txIsChild(childBucket, src, dest)
  405. return nil
  406. })
  407. return t, f
  408. }
  409. func (s *DB) txIsChild(b *bolt.Bucket, src DBRef, dest DBRef) (string, bool) {
  410. v := b.Get(src.ChildKey(dest))
  411. if v != nil {
  412. return string(v), true
  413. }
  414. return "", false
  415. }
  416. func (s *DB) Link(parentID DBRef, childID DBRef, linkType string) error {
  417. return s.db.Update(func(tx *bolt.Tx) error {
  418. childBucket := tx.Bucket([]byte("child"))
  419. parentBucket := tx.Bucket([]byte("parent"))
  420. return s.txLink(childBucket, parentBucket, parentID, childID, linkType)
  421. })
  422. }
  423. func (s *DB) txLink(childBucket *bolt.Bucket, parentBucket *bolt.Bucket, parentID DBRef, childID DBRef, linkType string) error {
  424. //fmt.Printf("txLink attempting to put %d inside %d\n", childID, parentID)
  425. prevParentID, found := s.txGetParent(parentBucket, childID)
  426. if found {
  427. //fmt.Printf("txLink removing %d from previous parent %d\n", childID, prevParentID)
  428. err := s.txUnlink(childBucket, parentBucket, prevParentID, childID)
  429. if err != nil {
  430. return err
  431. }
  432. }
  433. err := childBucket.Put(parentID.ChildKey(childID), []byte(linkType))
  434. if err != nil {
  435. return err
  436. }
  437. err = parentBucket.Put(childID.Key(), parentID.Key())
  438. if err != nil {
  439. return err
  440. }
  441. if DEBUG {
  442. fmt.Printf("txLink parent: %d child: %d\n", parentID, childID)
  443. }
  444. return nil
  445. }
  446. func (s *DB) Unlink(src DBRef, dest DBRef) error {
  447. return s.db.Update(func(tx *bolt.Tx) error {
  448. childBucket := tx.Bucket([]byte("child"))
  449. parentBucket := tx.Bucket([]byte("parent"))
  450. return s.txUnlink(childBucket, parentBucket, src, dest)
  451. })
  452. }
  453. func (s *DB) txUnlink(childBucket *bolt.Bucket, parentBucket *bolt.Bucket, parentID DBRef, childID DBRef) error {
  454. err := childBucket.Delete(parentID.ChildKey(childID))
  455. if err != nil {
  456. return err
  457. }
  458. err = parentBucket.Delete(childID.Key())
  459. if err != nil {
  460. return err
  461. }
  462. if DEBUG {
  463. fmt.Printf("txUnlink parent: %d child: %d\n", parentID, childID)
  464. }
  465. return nil
  466. }
  467. func (s *DB) txDelete(b *bolt.Bucket, id DBRef) error {
  468. if DEBUG {
  469. fmt.Printf("txDelete %d\n", id)
  470. }
  471. return b.Delete(id.Key())
  472. }