1/*
2 * Copyright (c) 2013 IBM Corp.
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 *    Seth Hoenig
11 *    Allan Stockdill-Mander
12 *    Mike Robertson
13 */
14
15package mqtt
16
17import (
18	"sync"
19
20	"github.com/eclipse/paho.mqtt.golang/packets"
21)
22
23// MemoryStore implements the store interface to provide a "persistence"
24// mechanism wholly stored in memory. This is only useful for
25// as long as the client instance exists.
26type MemoryStore struct {
27	sync.RWMutex
28	messages map[string]packets.ControlPacket
29	opened   bool
30}
31
32// NewMemoryStore returns a pointer to a new instance of
33// MemoryStore, the instance is not initialized and ready to
34// use until Open() has been called on it.
35func NewMemoryStore() *MemoryStore {
36	store := &MemoryStore{
37		messages: make(map[string]packets.ControlPacket),
38		opened:   false,
39	}
40	return store
41}
42
43// Open initializes a MemoryStore instance.
44func (store *MemoryStore) Open() {
45	store.Lock()
46	defer store.Unlock()
47	store.opened = true
48	DEBUG.Println(STR, "memorystore initialized")
49}
50
51// Put takes a key and a pointer to a Message and stores the
52// message.
53func (store *MemoryStore) Put(key string, message packets.ControlPacket) {
54	store.Lock()
55	defer store.Unlock()
56	if !store.opened {
57		ERROR.Println(STR, "Trying to use memory store, but not open")
58		return
59	}
60	store.messages[key] = message
61}
62
63// Get takes a key and looks in the store for a matching Message
64// returning either the Message pointer or nil.
65func (store *MemoryStore) Get(key string) packets.ControlPacket {
66	store.RLock()
67	defer store.RUnlock()
68	if !store.opened {
69		ERROR.Println(STR, "Trying to use memory store, but not open")
70		return nil
71	}
72	mid := mIDFromKey(key)
73	m := store.messages[key]
74	if m == nil {
75		CRITICAL.Println(STR, "memorystore get: message", mid, "not found")
76	} else {
77		DEBUG.Println(STR, "memorystore get: message", mid, "found")
78	}
79	return m
80}
81
82// All returns a slice of strings containing all the keys currently
83// in the MemoryStore.
84func (store *MemoryStore) All() []string {
85	store.RLock()
86	defer store.RUnlock()
87	if !store.opened {
88		ERROR.Println(STR, "Trying to use memory store, but not open")
89		return nil
90	}
91	keys := []string{}
92	for k := range store.messages {
93		keys = append(keys, k)
94	}
95	return keys
96}
97
98// Del takes a key, searches the MemoryStore and if the key is found
99// deletes the Message pointer associated with it.
100func (store *MemoryStore) Del(key string) {
101	store.Lock()
102	defer store.Unlock()
103	if !store.opened {
104		ERROR.Println(STR, "Trying to use memory store, but not open")
105		return
106	}
107	mid := mIDFromKey(key)
108	m := store.messages[key]
109	if m == nil {
110		WARN.Println(STR, "memorystore del: message", mid, "not found")
111	} else {
112		delete(store.messages, key)
113		DEBUG.Println(STR, "memorystore del: message", mid, "was deleted")
114	}
115}
116
117// Close will disallow modifications to the state of the store.
118func (store *MemoryStore) Close() {
119	store.Lock()
120	defer store.Unlock()
121	if !store.opened {
122		ERROR.Println(STR, "Trying to close memory store, but not open")
123		return
124	}
125	store.opened = false
126	DEBUG.Println(STR, "memorystore closed")
127}
128
129// Reset eliminates all persisted message data in the store.
130func (store *MemoryStore) Reset() {
131	store.Lock()
132	defer store.Unlock()
133	if !store.opened {
134		ERROR.Println(STR, "Trying to reset memory store, but not open")
135	}
136	store.messages = make(map[string]packets.ControlPacket)
137	WARN.Println(STR, "memorystore wiped")
138}
139