No Description

db.go 11KB

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