#include "common.h" #include "posdb.h" #include "log.h" #include "sha1.h" #include #include #include #include #include PosDb::PosDb(const char * fn) : log(fn) { // read in the log for(std::list::const_iterator p = log.begin(); p != log.end(); ++p) acceptLogEntry(*p); } void PosDb::acceptLogEntry(const LogEntry & l) { serial_to_object[l.serial] = l; switch(l.type) { case ET_HASH: { SHA1Hash h; h.set((unsigned char *)l.HashChange.hash); if(l.HashChange.add) { // verify hash not associated with anything for(ath_it p = account_to_hash.begin(); p != account_to_hash.end(); ++p) { if(p->second == h) { fprintf(stderr, "PosDb: Log associates a hash" " with more than one account! Aborting."); abort(); } } account_to_hash.insert(std::pair(l.HashChange.uid, h)); } else { // verify hash associated with something ath_it p; for(p = account_to_hash.begin(); p != account_to_hash.end(); ++p) { if(p->second == h) break; } if(p == account_to_hash.end()) { fprintf(stderr, "PosDb: Log deassociates an" "unassociated hash! Aborting."); abort(); } else { account_to_hash.erase(p); } } break; } case ET_TRANS: { atb_it q = account_to_balance.find(l.Transaction.uid); if(q == account_to_balance.end()) account_to_balance[l.Transaction.uid] = l.Transaction.delta; else q->second += l.Transaction.delta; break; } case ET_SALE: { uts_it q = upc_to_stock.find(l.StockChange.upc); if(q == upc_to_stock.end()) upc_to_stock[l.StockChange.upc] = l.StockChange.delta; else q->second += l.StockChange.delta; break; } case ET_PRICE: { upc_to_price[l.PriceChange.upc] = l.PriceChange.price; break; } case ET_ADDUPC: { upc_to_name[l.AddUPC.upc] = l.AddUPC.name; break; } case ET_REVERT: { sto_it q = serial_to_object.find(l.Revert.revert_serial); if((q == serial_to_object.end()) || (q->second.type != ET_TRANS)) { fprintf(stderr, "PosDb: Log reverts an invalid object! Aborting."); abort(); } else { account_to_balance[q->second.Transaction.uid] -= q->second.Transaction.delta; } break; } } } uint32_t PosDb::getAccountFromHash(const SHA1Hash & hash) { ath_it p; for(p = account_to_hash.begin(); p != account_to_hash.end(); ++p) { if(p->second == hash) break; } if(p == account_to_hash.end()) return 0; else return p->first; } std::list PosDb::getHashesFromAccount(uint32_t account) { std::list result; ath_it_r range = account_to_hash.equal_range(account); for(ath_it p = range.first; p != range.second; ++p) result.push_back(p->second.toHex()); return result; } std::list PosDb::getHashesFromAccount(std::string account) { return getHashesFromAccount(ns.get_id(account)); } int32_t PosDb::getAccountBalance(const SHA1Hash & hash) { uint32_t acct = getAccountFromHash(hash); if(!acct) return 0; else { atb_it p = account_to_balance.find(acct); if(p == account_to_balance.end()) return 0; else return p->second; } } int32_t PosDb::getAccountBalance(uint32_t account) { atb_it p = account_to_balance.find(account); if(p == account_to_balance.end()) return 0; else return p->second; } int32_t PosDb::getAccountBalance(std::string account) { return getAccountBalance(ns.get_id(account)); } uint64_t PosDb::associateHash(const SHA1Hash & hash, uint32_t account) { // verify hash not associated with anything if(getAccountFromHash(hash)) { return 0; } else { LogEntry l = log.newLogEntry(ET_HASH); l.HashChange.uid = account; l.HashChange.add = true; hash.get((unsigned char *)l.HashChange.hash); acceptLogEntry(l); return log.writeEntry(l); } } uint64_t PosDb::associateHash(const SHA1Hash & hash, std::string account) { return associateHash(hash, ns.get_id(account)); } uint64_t PosDb::deassociateHash(const SHA1Hash & hash) { // verify hash associated with something uint32_t acct = getAccountFromHash(hash); if(!acct) { return 0; } else { LogEntry l = log.newLogEntry(ET_HASH); l.HashChange.uid = acct; l.HashChange.add = false; hash.get((unsigned char *)l.HashChange.hash); acceptLogEntry(l); return log.writeEntry(l); } } int32_t PosDb::getUPCPrice(uint64_t upc) { uts_it it = upc_to_price.find(upc); if (it == upc_to_price.end()) { return 0; } return it->second; } uint64_t PosDb::setUPCPrice(uint64_t upc, int32_t price) { LogEntry l = log.newLogEntry(ET_PRICE); l.PriceChange.upc = upc; l.PriceChange.price = price; acceptLogEntry(l); return log.writeEntry(l); } // NOTE: this in theory could be deprecated. The client should // probably get the uid from the hash before doing a transaction. uint64_t PosDb::doTransaction(const SHA1Hash & hash, int32_t delta) { // verify hash associated with something uint32_t acct = getAccountFromHash(hash); if(!acct) { return 0; } else { LogEntry l = log.newLogEntry(ET_TRANS); l.Transaction.delta = delta; l.Transaction.uid = acct; acceptLogEntry(l); return log.writeEntry(l); } } uint64_t PosDb::doTransaction(const uint32_t account, int32_t delta) { LogEntry l = log.newLogEntry(ET_TRANS); l.Transaction.delta = delta; l.Transaction.uid = account; acceptLogEntry(l); return log.writeEntry(l); } uint64_t PosDb::doTransaction(std::string account, int32_t delta) { return doTransaction(ns.get_id(account), delta); } uint64_t PosDb::revertTransaction(uint64_t serial) { if(serial_to_object.find(serial) == serial_to_object.end()) { return 0; } else { // do not double-revert transactions sto_it p; for(p = serial_to_object.begin(); p != serial_to_object.end(); ++p) { if((p->second.type == ET_REVERT) && (p->second.Revert.revert_serial == serial)) break; } if(p != serial_to_object.end()) return 0; LogEntry l = log.newLogEntry(ET_REVERT); l.Revert.revert_serial = serial; acceptLogEntry(l); return log.writeEntry(l); } } int32_t PosDb::getStock(uint64_t upc) { uts_it p = upc_to_stock.find(upc); if(p == upc_to_stock.end()) return 0; else return p->second; } uint64_t PosDb::doStockChange(uint64_t upc, int32_t delta) { LogEntry l = log.newLogEntry(ET_SALE); l.StockChange.delta = delta; l.StockChange.upc = upc; acceptLogEntry(l); return log.writeEntry(l); } std::string PosDb::getUPCName(uint64_t upc) { std::map::iterator it = upc_to_name.find(upc); if(it == upc_to_name.end()) return "UNKNOWN UPC"; return upc_to_name[upc]; } uint64_t PosDb::setUPCName (uint64_t upc, std::string name) { LogEntry l = log.newLogEntry(ET_ADDUPC); l.AddUPC.upc = upc; strncpy(l.AddUPC.name, name.c_str(), 32); l.AddUPC.name[32] = 0; acceptLogEntry(l); return log.writeEntry(l); } std::vector PosDb::toString() { return log.toString(); }