mirror of
https://github.com/AskDavis/Casinotest.git
synced 2026-01-01 05:05:57 -08:00
Compare commits
19 Commits
2.0.0.0
...
WalletServ
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f961bbcaf | ||
|
|
336757fb55 | ||
|
|
34c622e0f0 | ||
|
|
7622169321 | ||
|
|
dba5caeac4 | ||
|
|
e39da3a52a | ||
|
|
9892f8b147 | ||
|
|
6a849dad4e | ||
|
|
b0c11f8974 | ||
|
|
093b9ec1ff | ||
|
|
7497a0233e | ||
|
|
df82a9e0c7 | ||
|
|
d325409101 | ||
|
|
ce170d8ad7 | ||
|
|
70ee980532 | ||
|
|
5cebe42a99 | ||
|
|
1ac9b40ec5 | ||
|
|
9fceb7451e | ||
|
|
b7d81c6e32 |
92321
Makefile.Debug
92321
Makefile.Debug
File diff suppressed because one or more lines are too long
92323
Makefile.Release
92323
Makefile.Release
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
<h2>Please download the updated wallet asap, hard fork incoming at block 546250</h2>
|
||||
[Click here to download the most recent wallet version -> 1.3.0 (Updated on July, 18 2014)](https://github.com/casinocoin/casinocoin/releases/tag/1.3.0.0 "Click to go to releases page")
|
||||
<h2>Wallet 2.0.0.0 Release available</h2>
|
||||
[Click here to download the most recent wallet version -> 2.0.0.0 (Updated on December, 3 2015)](https://github.com/casinocoin/casinocoin/releases/tag/2.0.0.0 "Click to go to releases page")
|
||||
|
||||
<p align="center"><img src="https://raw.github.com/transcoder/CasinoCoin/master/src/qt/res/images/logo.png" /></p>
|
||||
|
||||
|
||||
@@ -239,7 +239,12 @@ HEADERS += src/qt/bitcoingui.h \
|
||||
src/qt/qtquick_controls/cpp/qmlexchangeslistmodel.h \
|
||||
src/qt/qtquick_controls/cpp/qmlexchangeslistitem.h \
|
||||
src/qt/qtquick_controls/cpp/guiexchangeslistview.h \
|
||||
src/qt/qtquick_controls/cpp/guiexchangescontrol.h
|
||||
src/qt/qtquick_controls/cpp/guiexchangescontrol.h \
|
||||
src/walletserver.h \
|
||||
src/stomp/helpers.h \
|
||||
src/stomp/booststomp.h \
|
||||
src/stomp/stompframe.h \
|
||||
src/walletserversession.h
|
||||
|
||||
SOURCES += src/qt/bitcoin.cpp \
|
||||
src/qt/bitcoingui.cpp \
|
||||
@@ -340,7 +345,14 @@ SOURCES += src/qt/bitcoin.cpp \
|
||||
src/qt/qtquick_controls/cpp/qmlexchangeslistmodel.cpp \
|
||||
src/qt/qtquick_controls/cpp/qmlexchangeslistitem.cpp \
|
||||
src/qt/qtquick_controls/cpp/guiexchangeslistview.cpp \
|
||||
src/qt/qtquick_controls/cpp/guiexchangescontrol.cpp
|
||||
src/qt/qtquick_controls/cpp/guiexchangescontrol.cpp \
|
||||
src/walletserver.cpp \
|
||||
src/stomp/helpers.cpp \
|
||||
src/stomp/booststomp.cpp \
|
||||
src/stomp/stompframe.cpp \
|
||||
src/walletsession.cpp \
|
||||
src/json/json_spirit_value.cpp \
|
||||
src/walletserversession.cpp
|
||||
|
||||
RESOURCES += src/qt/bitcoin.qrc
|
||||
|
||||
@@ -455,6 +467,6 @@ LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX -lpthread
|
||||
# -lgdi32 has to happen after -lcrypto (see #681)
|
||||
LIBS += -lws2_32 -lole32 -lmswsock -loleaut32 -luuid -lgdi32 -lshlwapi
|
||||
LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX
|
||||
LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX
|
||||
LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX -lboost_serialization$$BOOST_LIB_SUFFIX
|
||||
|
||||
system($$QMAKE_LRELEASE -silent $$TRANSLATIONS)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 3.5.0, 2015-12-01T22:30:06. -->
|
||||
<!-- Written by QtCreator 3.5.0, 2016-03-24T23:27:30. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
@@ -120,7 +120,7 @@
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/a.jochems/Documents/GitHub/casinocoin-GUI-2.0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/a.jochems/Documents/GitHub/casinocoin-WalletServer</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
@@ -227,8 +227,8 @@
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">casinocoin-qt-windows</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:C:/Users/a.jochems/Documents/GitHub/casinocoin-GUI-2.0/casinocoin-qt-windows.pro</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">casinocoin-qt-windows2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:C:/Users/a.jochems/Documents/GitHub/casinocoin-WalletServer/casinocoin-qt-windows.pro</value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">casinocoin-qt-windows.pro</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
|
||||
|
||||
89
contrib/casinocoinUser.ldif
Normal file
89
contrib/casinocoinUser.ldif
Normal file
@@ -0,0 +1,89 @@
|
||||
version: 1
|
||||
dn: cn=schema
|
||||
changetype: modify
|
||||
add: attributeTypes
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.2
|
||||
NAME 'gender'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.3
|
||||
NAME 'country'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.4
|
||||
NAME 'nickName'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.5
|
||||
NAME 'timeZone'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.6
|
||||
NAME 'dateOfBirth'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.7
|
||||
NAME 'role'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.8
|
||||
NAME 'im'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.9
|
||||
NAME 'url'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.10
|
||||
NAME 'otherPhone'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.11
|
||||
NAME 'privatePersonalIdentifier'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.12
|
||||
NAME 'profileconfiguration'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.13
|
||||
NAME 'prefferedLanguage'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.14
|
||||
NAME 'organizationName'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.15
|
||||
NAME 'accountLocked'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
attributeTypes: ( 1.3.6.1.4.1.37505.1.16
|
||||
NAME 'passwordTimestamp'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
|
||||
-
|
||||
add: objectClasses
|
||||
objectClasses: ( 1.3.6.1.4.1.37505.1.1
|
||||
NAME 'casinocoinUser'
|
||||
DESC 'casinocoinUser'
|
||||
SUP inetOrgPerson
|
||||
STRUCTURAL
|
||||
MAY ( gender $ country $ nickName $ timeZone $ dateOfBirth $ role $ im $ url $ otherPhone $ privatePersonalIdentifier $ profileconfiguration $ prefferedLanguage $ organizationName $ accountLocked $ passwordTimestamp)
|
||||
)
|
||||
-
|
||||
71
contrib/casinocoinUser.schema
Normal file
71
contrib/casinocoinUser.schema
Normal file
@@ -0,0 +1,71 @@
|
||||
attributetype ( 1.1.1.301.1
|
||||
NAME 'country'
|
||||
DESC 'Country of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.2
|
||||
NAME 'role'
|
||||
DESC 'Role of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.3
|
||||
NAME 'im'
|
||||
DESC 'IM of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.4
|
||||
NAME 'profileConfiguration'
|
||||
DESC 'Profile Configuration of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.5
|
||||
NAME 'url'
|
||||
DESC 'URL Configuration of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.7
|
||||
NAME 'accountLocked'
|
||||
DESC 'Stores the status if a user account is locked'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.8
|
||||
NAME 'passwordTimestamp'
|
||||
DESC 'Timestamp of last password change'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.9
|
||||
NAME 'scimId'
|
||||
DESC 'scimId'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.10
|
||||
NAME 'lastModifiedDate'
|
||||
DESC 'User last modifation date'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.11
|
||||
NAME 'createdDate'
|
||||
DESC 'User creaetion date'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.12
|
||||
NAME 'location'
|
||||
DESC 'User location'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.13
|
||||
NAME 'unlockTime'
|
||||
DESC 'User Unlock Time'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.14
|
||||
NAME 'failedLoginAttempts'
|
||||
DESC 'User Failed Login Attempts'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
objectclass ( 1.1.1.302.1
|
||||
NAME 'casinocoinUser'
|
||||
DESC 'Casinocoin user'
|
||||
SUP inetOrgPerson
|
||||
STRUCTURAL
|
||||
MAY ( country $ role $ im $ profileConfiguration $ url $ accountLocked $ passwordTimestamp $ scimId $ lastModifiedDate $ createdDate $ location $ unlockTime $ failedLoginAttempts ) )
|
||||
63
contrib/casinocoind.conf
Normal file
63
contrib/casinocoind.conf
Normal file
@@ -0,0 +1,63 @@
|
||||
description "Casinocoin Core Daemon"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on starting rc RUNLEVEL=[016]
|
||||
|
||||
env CASINOCOIND_BIN="/usr/bin/casinocoind"
|
||||
env CASINOCOIND_USER="ubuntu"
|
||||
env CASINOCOIND_GROUP="ubuntu"
|
||||
env CASINOCOIND_PIDDIR="/var/run/casinocoind"
|
||||
# upstart can't handle variables constructed with other variables
|
||||
env CASINOCOIND_PIDFILE="/var/run/casinocoind/casinocoind.pid"
|
||||
env CASINOCOIND_CONFIGFILE="/u01/CSC/.casinocoin/casinocoin.conf"
|
||||
env CASINOCOIND_DATADIR="/u01/CSC/data"
|
||||
|
||||
expect fork
|
||||
|
||||
respawn
|
||||
respawn limit 5 120
|
||||
kill timeout 60
|
||||
|
||||
pre-start script
|
||||
# this will catch non-existent config files
|
||||
# bitcoind will check and exit with this very warning, but it can do so
|
||||
# long after forking, leaving upstart to think everything started fine.
|
||||
# since this is a commonly encountered case on install, just check and
|
||||
# warn here.
|
||||
if ! grep -qs '^rpcpassword=' "$CASINOCOIND_CONFIGFILE" ; then
|
||||
echo "ERROR: You must set a secure rpcpassword to run casinocoind."
|
||||
echo "The setting must appear in $CASINOCOIND_CONFIGFILE"
|
||||
echo
|
||||
echo "This password is security critical to securing wallets "
|
||||
echo "and must not be the same as the rpcuser setting."
|
||||
echo "You can generate a suitable random password using the following"
|
||||
echo "command from the shell:"
|
||||
echo
|
||||
echo "bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'"
|
||||
echo
|
||||
echo "It is also recommended that you also set alertnotify so you are "
|
||||
echo "notified of problems:"
|
||||
echo
|
||||
echo "ie: alertnotify=echo %%s | mail -s \"Casinocoin Alert\"" \
|
||||
"admin@foo.com"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$CASINOCOIND_PIDDIR"
|
||||
chmod 0755 "$CASINOCOIND_PIDDIR"
|
||||
chown $CASINOCOIND_USER:$CASINOCOIND_GROUP "$CASINOCOIND_PIDDIR"
|
||||
chown $CASINOCOIND_USER:$CASINOCOIND_GROUP "$CASINOCOIND_CONFIGFILE"
|
||||
chmod 0660 "$CASINOCOIND_CONFIGFILE"
|
||||
end script
|
||||
|
||||
exec start-stop-daemon \
|
||||
--start \
|
||||
--pidfile "$CASINOCOIND_PIDFILE" \
|
||||
--chuid $CASINOCOIND_USER:$CASINOCOIND_GROUP \
|
||||
--exec "$CASINOCOIND_BIN" \
|
||||
-- \
|
||||
-pid="$CASINOCOIND_PIDFILE" \
|
||||
-conf="$CASINOCOIND_CONFIGFILE" \
|
||||
-datadir="$CASINOCOIND_DATADIR" \
|
||||
-daemon
|
||||
4
contrib/walletserver/1-enable_ppolicy.ldif
Normal file
4
contrib/walletserver/1-enable_ppolicy.ldif
Normal file
@@ -0,0 +1,4 @@
|
||||
dn: cn=module{0},cn=config
|
||||
changetype: modify
|
||||
add: olcModuleLoad
|
||||
olcModuleLoad: ppolicy.la
|
||||
5
contrib/walletserver/2-create_default_policy.ldif
Normal file
5
contrib/walletserver/2-create_default_policy.ldif
Normal file
@@ -0,0 +1,5 @@
|
||||
dn: ou=Policies,dc=casinocoin,dc=org
|
||||
objectClass: top
|
||||
objectClass: organizationalUnit
|
||||
ou: Policies
|
||||
description: Default password policies container
|
||||
6
contrib/walletserver/3-ppolicy_overlay.ldif
Normal file
6
contrib/walletserver/3-ppolicy_overlay.ldif
Normal file
@@ -0,0 +1,6 @@
|
||||
dn: olcOverlay={0}ppolicy,olcDatabase={1}hdb,cn=config
|
||||
objectClass: olcOverlayConfig
|
||||
objectClass: olcPPolicyConfig
|
||||
olcOverlay: {0}ppolicy
|
||||
olcPPolicyDefault: cn=DefaultPPolicy,ou=Policies,dc=casinocoin,dc=org
|
||||
olcPPolicyHashCleartext: TRUE
|
||||
19
contrib/walletserver/4-ppolicy-default.ldif
Normal file
19
contrib/walletserver/4-ppolicy-default.ldif
Normal file
@@ -0,0 +1,19 @@
|
||||
dn: cn=DefaultPPolicy,ou=Policies,dc=casinocoin,dc=org
|
||||
cn: DefaultPPolicy
|
||||
objectClass: pwdPolicy
|
||||
objectClass: device
|
||||
objectClass: top
|
||||
pwdAttribute: userPassword
|
||||
pwdMaxAge: 2419200
|
||||
pwdExpireWarning: 1814400
|
||||
pwdInHistory: 3
|
||||
pwdCheckQuality: 1
|
||||
pwdMinLength: 8
|
||||
pwdMaxFailure: 3
|
||||
pwdLockout: TRUE
|
||||
pwdLockoutDuration: 600
|
||||
pwdGraceAuthNLimit: 0
|
||||
pwdFailureCountInterval: 0
|
||||
pwdMustChange: TRUE
|
||||
pwdAllowUserChange: TRUE
|
||||
pwdSafeModify: FALSE
|
||||
4
contrib/walletserver/5-uid_index.ldif
Normal file
4
contrib/walletserver/5-uid_index.ldif
Normal file
@@ -0,0 +1,4 @@
|
||||
dn: olcDatabase={1}hdb,cn=config
|
||||
changetype: modify
|
||||
add: olcDbIndex
|
||||
olcDbIndex: uid eq,pres,sub
|
||||
4
contrib/walletserver/6-mail_index.ldif
Normal file
4
contrib/walletserver/6-mail_index.ldif
Normal file
@@ -0,0 +1,4 @@
|
||||
dn: olcDatabase={1}hdb,cn=config
|
||||
changetype: modify
|
||||
add: olcDbIndex
|
||||
olcDbIndex: mail eq,pres,sub
|
||||
8
contrib/walletserver/7-schema_convert.conf
Normal file
8
contrib/walletserver/7-schema_convert.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
include /etc/ldap/schema/core.schema
|
||||
include /etc/ldap/schema/cosine.schema
|
||||
include /etc/ldap/schema/inetorgperson.schema
|
||||
include /etc/ldap/schema/misc.schema
|
||||
include /etc/ldap/schema/nis.schema
|
||||
include /etc/ldap/schema/openldap.schema
|
||||
include /etc/ldap/schema/ppolicy.schema
|
||||
include /etc/ldap/schema/casinocoinUser.schema
|
||||
4
contrib/walletserver/8-logging.ldif
Normal file
4
contrib/walletserver/8-logging.ldif
Normal file
@@ -0,0 +1,4 @@
|
||||
dn: cn=config
|
||||
changetype: modify
|
||||
replace: olcLogLevel
|
||||
olcLogLevel: stats
|
||||
15
contrib/walletserver/9-casinocoinobjects.ldif
Normal file
15
contrib/walletserver/9-casinocoinobjects.ldif
Normal file
@@ -0,0 +1,15 @@
|
||||
dn: ou=Users,dc=casinocoin,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: Users
|
||||
|
||||
dn: ou=Groups,dc=casinocoin,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: Groups
|
||||
|
||||
dn: ou=WalletUsers,ou=Groups,dc=casinocoin,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: WalletUsers
|
||||
|
||||
dn: ou=WalletApplications,ou=Groups,dc=casinocoin,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: WalletApplications
|
||||
71
contrib/walletserver/casinocoinUser.schema
Normal file
71
contrib/walletserver/casinocoinUser.schema
Normal file
@@ -0,0 +1,71 @@
|
||||
attributetype ( 1.1.1.301.1
|
||||
NAME 'country'
|
||||
DESC 'Country of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.2
|
||||
NAME 'role'
|
||||
DESC 'Role of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.3
|
||||
NAME 'im'
|
||||
DESC 'IM of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.4
|
||||
NAME 'profileConfiguration'
|
||||
DESC 'Profile Configuration of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.5
|
||||
NAME 'url'
|
||||
DESC 'URL Configuration of a user'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.7
|
||||
NAME 'accountLocked'
|
||||
DESC 'Stores the status if a user account is locked'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.8
|
||||
NAME 'passwordTimestamp'
|
||||
DESC 'Timestamp of last password change'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.9
|
||||
NAME 'scimId'
|
||||
DESC 'scimId'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.10
|
||||
NAME 'lastModifiedDate'
|
||||
DESC 'User last modifation date'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.11
|
||||
NAME 'createdDate'
|
||||
DESC 'User creaetion date'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.12
|
||||
NAME 'location'
|
||||
DESC 'User location'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.13
|
||||
NAME 'unlockTime'
|
||||
DESC 'User Unlock Time'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
attributetype ( 1.1.1.301.14
|
||||
NAME 'failedLoginAttempts'
|
||||
DESC 'User Failed Login Attempts'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
objectclass ( 1.1.1.302.1
|
||||
NAME 'casinocoinUser'
|
||||
DESC 'Casinocoin user'
|
||||
SUP inetOrgPerson
|
||||
STRUCTURAL
|
||||
MAY ( country $ role $ im $ profileConfiguration $ url $ accountLocked $ passwordTimestamp $ scimId $ lastModifiedDate $ createdDate $ location $ unlockTime $ failedLoginAttempts ) )
|
||||
15
contrib/walletserver/casinocoinobjects.ldif
Normal file
15
contrib/walletserver/casinocoinobjects.ldif
Normal file
@@ -0,0 +1,15 @@
|
||||
dn: ou=Users,dc=casinocoin,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: Users
|
||||
|
||||
dn: ou=Groups,dc=casinocoin,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: Groups
|
||||
|
||||
dn: ou=WalletUsers,ou=Groups,dc=casinocoin,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: WalletUsers
|
||||
|
||||
dn: ou=WalletApplications,ou=Groups,dc=casinocoin,dc=org
|
||||
objectClass: organizationalUnit
|
||||
ou: WalletApplications
|
||||
35
contrib/walletserver/cn=casinocoinUser.ldif
Normal file
35
contrib/walletserver/cn=casinocoinUser.ldif
Normal file
@@ -0,0 +1,35 @@
|
||||
dn: cn=casinocoinuser,cn=schema,cn=config
|
||||
objectClass: olcSchemaConfig
|
||||
cn: casinocoinuser
|
||||
olcAttributeTypes: {0}( 1.1.1.301.1 NAME 'country' DESC 'Country of a user' SY
|
||||
NTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {1}( 1.1.1.301.2 NAME 'role' DESC 'Role of a user' SYNTAX 1
|
||||
.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {2}( 1.1.1.301.3 NAME 'im' DESC 'IM of a user' SYNTAX 1.3.6
|
||||
.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.1.1.301.4 NAME 'profileConfiguration' DESC 'Profile
|
||||
Configuration of a user' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.1.1.301.5 NAME 'url' DESC 'URL Configuration of a us
|
||||
er' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.1.1.301.7 NAME 'accountLocked' DESC 'Stores the stat
|
||||
us if a user account is locked' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-V
|
||||
ALUE )
|
||||
olcAttributeTypes: {6}( 1.1.1.301.8 NAME 'passwordTimestamp' DESC 'Timestamp o
|
||||
f last password change' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 1.1.1.301.9 NAME 'scimId' DESC 'scimId' SYNTAX 1.3.6.1
|
||||
.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.1.1.301.10 NAME 'lastModifiedDate' DESC 'User last m
|
||||
odifation date' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {9}( 1.1.1.301.11 NAME 'createdDate' DESC 'User creaetion d
|
||||
ate' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {10}( 1.1.1.301.12 NAME 'location' DESC 'User location' SYN
|
||||
TAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {11}( 1.1.1.301.13 NAME 'unlockTime' DESC 'User Unlock Time
|
||||
' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {12}( 1.1.1.301.14 NAME 'failedLoginAttempts' DESC 'User Fa
|
||||
iled Login Attempts' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcObjectClasses: {0}( 1.1.1.302.1 NAME 'casinocoinUser' DESC 'Casinocoin user
|
||||
' SUP inetOrgPerson STRUCTURAL MAY ( country $ role $ im $ profileConfigurati
|
||||
on $ url $ accountLocked $ passwordTimestamp $ scimId $ lastModifiedDate $ cr
|
||||
eatedDate $ location $ unlockTime $ failedLoginAttempts ) )
|
||||
|
||||
BIN
doc/WalletServer-Architecture.odp
Normal file
BIN
doc/WalletServer-Architecture.odp
Normal file
Binary file not shown.
8
doc/WalletServer-ErrorMessages.txt
Normal file
8
doc/WalletServer-ErrorMessages.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
100 - No arguments supplied for WalletServer command.
|
||||
101 - No Wallet ID supplied in arguments array.
|
||||
102 - Invalid Account ID for given Wallet ID.
|
||||
103 - Wallet file does not exist on WalletServer.
|
||||
104 - No passphrase supplied for wallet encryption.
|
||||
105 - Given SessionId is different than the one registered for AccountId.
|
||||
106 - No session exists for given AccountId.
|
||||
107 - Wallet Server could not parse the incomming message.
|
||||
231
doc/WalletServer-MessageDefinitions.txt
Normal file
231
doc/WalletServer-MessageDefinitions.txt
Normal file
@@ -0,0 +1,231 @@
|
||||
--
|
||||
-- Create Wallet
|
||||
--
|
||||
Request:
|
||||
{
|
||||
"command" : "createwallet",
|
||||
"accountid" : "andre@jochems.com",
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"arguments" : {
|
||||
"passphrase" : "mywalletsecret"
|
||||
}
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"result" : {
|
||||
"errorCode" : 0,
|
||||
"errorMessage" : "",
|
||||
"walletid" : "517beddb-8de2-4112-8aad-9e4d627916aa"
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
-- Open Wallet
|
||||
--
|
||||
Request:
|
||||
{
|
||||
"command" : "openwallet",
|
||||
"accountid" : "andre@jochems.com",
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"arguments" : {
|
||||
"walletid" : "517beddb-8de2-4112-8aad-9e4d627916aa",
|
||||
"passphrase" : "mywalletsecret"
|
||||
}
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"result" : {
|
||||
"errorCode" : 0,
|
||||
"errorMessage" : ""
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
-- Close Wallet
|
||||
--
|
||||
Request:
|
||||
{
|
||||
"command" : "closewallet",
|
||||
"accountid" : "andre@jochems.com",
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"arguments" : {
|
||||
"walletid" : "517beddb-8de2-4112-8aad-9e4d627916aa"
|
||||
}
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"result" : {
|
||||
"errorCode" : 0,
|
||||
"errorMessage" : ""
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
-- Get Wallet Info
|
||||
--
|
||||
Request:
|
||||
{
|
||||
"command" : "getinfo",
|
||||
"accountid" : "andre@jochems.com",
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"arguments" : {
|
||||
"walletid" : "517beddb-8de2-4112-8aad-9e4d627916aa"
|
||||
}
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"result" : {
|
||||
"errorCode" : 0,
|
||||
"errorMessage" : "",
|
||||
"balance" : 250.412323212,
|
||||
"blocks" : 1377377,
|
||||
"difficulty" : 21.41622924,
|
||||
"keypoololdest" : 1445349028,
|
||||
"keypoolsize" : 101,
|
||||
"lastTransactions" : [
|
||||
{ "txid" : "4378c3ffe1459bd5ff04ef19c9d56cfecaad45ae3bb0661768b42f9a40952bfa",
|
||||
"address" : "CT8YNXrn4EmPXTin4ecMtuWu1gvvUQuEKH",
|
||||
"category" : "receive",
|
||||
"amount" : 0.90000000,
|
||||
"confirmations" : 52920,
|
||||
"blockhash" : "96b0885392d5b316e3cdb4fe9be0327790f7135f517ca38e50d9b4f8599d85b6",
|
||||
"blockindex" : 1,
|
||||
"blocktime" : 1454950142,
|
||||
"time" : 1454950116,
|
||||
"timereceived" : 1454950116
|
||||
},
|
||||
{ "txid" : "610157549d6c2f62809ad245134e5cdbc38e2738907daf376e71f523d3b99e8a",
|
||||
"address" : "CVXzfjz3q1x3K8AeuCmhZ5cHK3ZzDgzURV",
|
||||
"category" : "send",
|
||||
"amount" : -1.00000000,
|
||||
"fee" : -0.00100000,
|
||||
"confirmations" : 66137,
|
||||
"blockhash" : "7fd6b63c8f6c7e2b8bc48935efa560a50d16a1733c69c0a1c66e49a8ba44c1be",
|
||||
"blockindex" : 1,
|
||||
"blocktime" : 1454405676,
|
||||
"time" : 1454405608,
|
||||
"timereceived" : 1454405608
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
-- Get Wallet Transactions
|
||||
--
|
||||
Request:
|
||||
{
|
||||
"command" : "listtransactions",
|
||||
"accountid" : "andre@jochems.com",
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"arguments" : {
|
||||
"walletid" : "517beddb-8de2-4112-8aad-9e4d627916aa",
|
||||
"count" : 10,
|
||||
"from" : 0
|
||||
}
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"result" : {
|
||||
"errorCode" : 0,
|
||||
"errorMessage" : "",
|
||||
"indexFrom" : 0,
|
||||
"indexTo" : 10,
|
||||
"transactions" : [
|
||||
{ "txid" : "4378c3ffe1459bd5ff04ef19c9d56cfecaad45ae3bb0661768b42f9a40952bfa",
|
||||
"address" : "CT8YNXrn4EmPXTin4ecMtuWu1gvvUQuEKH",
|
||||
"category" : "receive",
|
||||
"amount" : 0.90000000,
|
||||
"confirmations" : 52920,
|
||||
"blockhash" : "96b0885392d5b316e3cdb4fe9be0327790f7135f517ca38e50d9b4f8599d85b6",
|
||||
"blockindex" : 1,
|
||||
"blocktime" : 1454950142,
|
||||
"time" : 1454950116,
|
||||
"timereceived" : 1454950116
|
||||
},
|
||||
{ "txid" : "610157549d6c2f62809ad245134e5cdbc38e2738907daf376e71f523d3b99e8a",
|
||||
"address" : "CVXzfjz3q1x3K8AeuCmhZ5cHK3ZzDgzURV",
|
||||
"category" : "send",
|
||||
"amount" : -1.00000000,
|
||||
"fee" : -0.00100000,
|
||||
"confirmations" : 66137,
|
||||
"blockhash" : "7fd6b63c8f6c7e2b8bc48935efa560a50d16a1733c69c0a1c66e49a8ba44c1be",
|
||||
"blockindex" : 1,
|
||||
"blocktime" : 1454405676,
|
||||
"time" : 1454405608,
|
||||
"timereceived" : 1454405608
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
-- Get Address book
|
||||
--
|
||||
Request:
|
||||
{
|
||||
"command" : "getaddresslist",
|
||||
"accountid" : "andre@jochems.com",
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"arguments" : {
|
||||
"walletid" : "517beddb-8de2-4112-8aad-9e4d627916aa"
|
||||
}
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"result" : {
|
||||
"errorCode" : 0,
|
||||
"errorMessage" : ""
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
-- Send Coins
|
||||
--
|
||||
Request:
|
||||
{
|
||||
"command" : "sendtoaddress",
|
||||
"accountid" : "andre@jochems.com",
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"arguments" : {
|
||||
"walletid" : "517beddb-8de2-4112-8aad-9e4d627916aa",
|
||||
"address" : "AB3423SDSDFS",
|
||||
"amount" : 234.67854,
|
||||
"comment" : "Coins for a test transaction"
|
||||
}
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"sessionid" : "123123-12312321-123123123",
|
||||
"correlationid" : "65bb1cf4-3ca2-4d32-9a3c-9ae264424b0e",
|
||||
"result" : {
|
||||
"errorCode" : 0,
|
||||
"errorMessage" : ""
|
||||
}
|
||||
}
|
||||
@@ -266,6 +266,15 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "listlockunspent", &listlockunspent, false, false, true },
|
||||
{ "verifychain", &verifychain, true, false, false },
|
||||
{ "getcoinsupply", &getcoinsupply, true, false, false },
|
||||
{ "startwalletserversession", &startwalletserversession, true, false, false },
|
||||
{ "listwalletserversessions", &listwalletserversessions, true, false, false },
|
||||
{ "stopwalletserversession", &stopwalletserversession, true, false, false },
|
||||
{ "listwallets", &listwallets, true, false, false },
|
||||
{ "wsopenwallet", &wsopenwallet, true, false, false },
|
||||
{ "wsclosewallet", &wsclosewallet, true, false, false },
|
||||
{ "wsgetinfo", &wsgetinfo, true, false, false },
|
||||
{ "wsgetaddresslist", &wsgetaddresslist, true, false, false },
|
||||
{ "wssendtoaddress", &wssendtoaddress, true, false, false },
|
||||
};
|
||||
|
||||
CRPCTable::CRPCTable()
|
||||
|
||||
@@ -64,6 +64,9 @@ enum RPCErrorCode
|
||||
RPC_WALLET_WRONG_ENC_STATE = -15, // Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
|
||||
RPC_WALLET_ENCRYPTION_FAILED = -16, // Failed to encrypt the wallet
|
||||
RPC_WALLET_ALREADY_UNLOCKED = -17, // Wallet is already unlocked
|
||||
|
||||
// Wallet Server errors
|
||||
RPC_WALLETSERVER_INVALID_ID = -100, // Given identifier is already in a session
|
||||
};
|
||||
|
||||
json_spirit::Object JSONRPCError(int code, const std::string& message);
|
||||
@@ -207,5 +210,15 @@ extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp)
|
||||
extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp);
|
||||
|
||||
extern json_spirit::Value getcoinsupply(const json_spirit::Array& params, bool fHelp);
|
||||
//WalletServer RPC Commands
|
||||
extern json_spirit::Value startwalletserversession(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value listwalletserversessions(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value stopwalletserversession(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value listwallets(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value wsopenwallet(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value wsclosewallet(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value wsgetinfo(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value wsgetaddresslist(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value wssendtoaddress(const json_spirit::Array& params, bool fHelp);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it
|
||||
#define CLIENT_VERSION_MAJOR 2
|
||||
#define CLIENT_VERSION_MINOR 0
|
||||
#define CLIENT_VERSION_REVISION 0
|
||||
#define CLIENT_VERSION_REVISION 1
|
||||
#define CLIENT_VERSION_BUILD 0
|
||||
|
||||
// Set to true for release, false for prerelease or test build
|
||||
|
||||
21
src/init.cpp
21
src/init.cpp
@@ -8,8 +8,9 @@
|
||||
#include "bitcoinrpc.h"
|
||||
#include "net.h"
|
||||
#include "init.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "ui_interface.h"
|
||||
#include "walletserver.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
@@ -26,7 +27,9 @@ using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
CWallet* pwalletMain;
|
||||
WalletServer walletServer;
|
||||
CClientUIInterface uiInterface;
|
||||
boost::thread walletServerThread;
|
||||
|
||||
#ifdef WIN32
|
||||
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
|
||||
@@ -78,6 +81,9 @@ volatile bool fRequestShutdown = false;
|
||||
|
||||
void StartShutdown()
|
||||
{
|
||||
// Stop WalletServer if running
|
||||
StopWalletServerThread();
|
||||
// initiate shutdown
|
||||
boost::this_thread::sleep_for( boost::chrono::seconds( 1 ) );
|
||||
fRequestShutdown = true;
|
||||
}
|
||||
@@ -226,7 +232,9 @@ bool AppInit(int argc, char* argv[])
|
||||
fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
// WalletServer parameter
|
||||
fWalletServer = GetBoolArg("-walletserver");
|
||||
// create the thread to detect a shutdown
|
||||
detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup));
|
||||
fRet = AppInit2(threadGroup);
|
||||
}
|
||||
@@ -256,7 +264,6 @@ extern void noui_connect();
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
bool fRet = false;
|
||||
|
||||
// Connect bitcoind signal handlers
|
||||
noui_connect();
|
||||
|
||||
@@ -1130,6 +1137,14 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
if (pwalletMain)
|
||||
GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain);
|
||||
|
||||
// Start The WalletServer if defined
|
||||
fWalletServer = GetBoolArg("-walletserver", false);
|
||||
if (fWalletServer)
|
||||
{
|
||||
// Run a thread for the WalletServer
|
||||
threadGroup.create_thread(boost::bind(&StartWalletServerThread));
|
||||
}
|
||||
|
||||
// ********************************************************* Step 12: finished
|
||||
|
||||
uiInterface.InitMessage(_("Done loading"));
|
||||
|
||||
@@ -6,3 +6,7 @@
|
||||
// json spirit version 2.00
|
||||
|
||||
#include "json_spirit_value.h"
|
||||
|
||||
namespace json_spirit {
|
||||
const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"};
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
namespace json_spirit
|
||||
{
|
||||
enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type };
|
||||
static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"};
|
||||
extern const char* Value_type_name[];
|
||||
|
||||
template< class Config > // Config determines whether the value uses std::string or std::wstring and
|
||||
// whether JSON Objects are represented as vectors or maps
|
||||
|
||||
@@ -25,6 +25,8 @@ BOOST_SUFFIX?=-mgw49-mt-s-1_55
|
||||
|
||||
INCLUDEPATHS= \
|
||||
-I"$(CURDIR)" \
|
||||
-I"$(CURDIR)\stomp" \
|
||||
-I"$(CURDIR)\json" \
|
||||
-I"C:\deps\boost_1_55_0" \
|
||||
-I"C:\deps\db-4.8.30.NC\build_unix" \
|
||||
-I"C:\deps\openssl-1.0.2d\include" \
|
||||
@@ -45,6 +47,7 @@ LIBS= \
|
||||
-l boost_program_options$(BOOST_SUFFIX) \
|
||||
-l boost_thread$(BOOST_SUFFIX) \
|
||||
-l boost_chrono$(BOOST_SUFFIX) \
|
||||
-l boost_serialization$(BOOST_SUFFIX) \
|
||||
-l db_cxx \
|
||||
-l ssl \
|
||||
-l crypto
|
||||
@@ -106,7 +109,15 @@ OBJS= \
|
||||
obj/bloom.o \
|
||||
obj/noui.o \
|
||||
obj/leveldb.o \
|
||||
obj/txdb.o
|
||||
obj/txdb.o \
|
||||
obj/json/json_spirit_value.o \
|
||||
obj/json/json_spirit_reader.o \
|
||||
obj/json/json_spirit_writer.o \
|
||||
obj/stomp/helpers.o \
|
||||
obj/stomp/booststomp.o \
|
||||
obj/stomp/stompframe.o \
|
||||
obj/walletserver.o \
|
||||
obj/walletserversession.o
|
||||
|
||||
ifdef USE_SSE2
|
||||
DEFS += -DUSE_SSE2
|
||||
@@ -147,7 +158,8 @@ test_casinocoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
|
||||
|
||||
clean:
|
||||
rm -f casinocoind.exe test_casinocoin.exe
|
||||
rm -f obj/*
|
||||
rm -f obj/stomp/*
|
||||
rm -f obj/*.o
|
||||
rm -f obj-test/*
|
||||
cd leveldb && $(MAKE) TARGET_OS=NATIVE_WINDOWS clean && cd ..
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ LIBS += \
|
||||
-l boost_filesystem$(BOOST_LIB_SUFFIX) \
|
||||
-l boost_program_options$(BOOST_LIB_SUFFIX) \
|
||||
-l boost_thread$(BOOST_LIB_SUFFIX) \
|
||||
-l boost_serialization$(BOOST_LIB_SUFFIX) \
|
||||
-l db_cxx$(BDB_LIB_SUFFIX) \
|
||||
-l ssl \
|
||||
-l crypto
|
||||
@@ -126,6 +127,9 @@ xCXXFLAGS=-O2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-para
|
||||
# adds some defaults in front. Unfortunately, LDFLAGS=... $(LDFLAGS) does not work.
|
||||
xLDFLAGS=$(LDHARDENING) $(LDFLAGS)
|
||||
|
||||
HEADERS = $(wildcard *.h) \
|
||||
stomp/$(wildcar *.h)
|
||||
|
||||
OBJS= \
|
||||
leveldb/libleveldb.a \
|
||||
obj/alert.o \
|
||||
@@ -158,7 +162,11 @@ OBJS= \
|
||||
obj/bloom.o \
|
||||
obj/noui.o \
|
||||
obj/leveldb.o \
|
||||
obj/txdb.o
|
||||
obj/txdb.o \
|
||||
obj/stomp/helpers.o \
|
||||
obj/stomp/booststomp.o \
|
||||
obj/stomp/stompframe.o \
|
||||
obj/walletserver.o
|
||||
|
||||
|
||||
ifdef USE_SSE2
|
||||
@@ -199,6 +207,7 @@ obj/%-sse2.o: %-sse2.cpp
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/%.o: %.cpp
|
||||
mkdir -p obj/stomp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
QString getDescription() const{ return m_strDescription; }
|
||||
double getLastBidPriceBTC() const{ return m_dblLastBidPriceBTC; }
|
||||
double getLastAskPriceBTC() const{ return m_dblLastAskPriceBTC; }
|
||||
double getLastPriceBTC() const{ return m_dblLastBidPriceBTC; }
|
||||
double getLastPriceBTC() const{ return m_dblLastPriceBTC; }
|
||||
double getVolume24H() const{ return m_dblVolume24H; }
|
||||
QString getLastUpdateTime() const{ return m_strLastUpdateTime; }
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "ui_interface.h"
|
||||
#include "paymentserver.h"
|
||||
#include "splashscreen.h"
|
||||
#include "walletserver.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#if QT_VERSION < 0x050000
|
||||
@@ -296,6 +297,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shutdown the core and its threads
|
||||
threadGroup.interrupt_all();
|
||||
threadGroup.join_all();
|
||||
Shutdown();
|
||||
|
||||
@@ -473,7 +473,7 @@ void BitcoinGUI::restoreWindowGeometry()
|
||||
{
|
||||
QSettings settings;
|
||||
QPoint pos = settings.value("nWindowPos").toPoint();
|
||||
QSize size = settings.value("nWindowSize", QSize(850, 550)).toSize();
|
||||
QSize size = settings.value("nWindowSize", QSize(900, 650)).toSize();
|
||||
if (!pos.x() && !pos.y())
|
||||
{
|
||||
QRect screen = QApplication::desktop()->screenGeometry();
|
||||
|
||||
@@ -73,10 +73,14 @@ QString Currencies::symbol(int currency)
|
||||
}
|
||||
}
|
||||
|
||||
QString Currencies::format(int currency, double value, bool useSymbol)
|
||||
QString Currencies::format(int currency, double value, bool useSymbol, int decimals, bool isSatoshi)
|
||||
{
|
||||
// divide by satoshi
|
||||
double fiatValue = value * 0.00000001;
|
||||
double fiatValue = value;
|
||||
if(isSatoshi)
|
||||
{
|
||||
fiatValue *= 0.00000001;
|
||||
}
|
||||
QString formattedValue = "";
|
||||
if(useSymbol)
|
||||
{
|
||||
@@ -84,7 +88,7 @@ QString Currencies::format(int currency, double value, bool useSymbol)
|
||||
}
|
||||
// apply format
|
||||
QLocale::setDefault( QLocale(QLocale::English, QLocale::UnitedStates) );
|
||||
formattedValue.append(QString("%L1").arg(fiatValue, 0, 'f', 2)).append(" ").append(name(currency));
|
||||
formattedValue.append(QString("%L1").arg(fiatValue, 0, 'f', decimals)).append(" ").append(name(currency));
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
//! symbol
|
||||
static QString symbol(int currency);
|
||||
//! Format value
|
||||
static QString format(int currency, double value, bool symbol);
|
||||
static QString format(int currency, double value, bool symbol, int decimals, bool isSatoshi);
|
||||
|
||||
//! @name AbstractListModel implementation
|
||||
//! List model for currency drop-down selection box.
|
||||
|
||||
@@ -410,7 +410,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="lblConnections">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
@@ -423,7 +423,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="txtConnections">
|
||||
<property name="font">
|
||||
<font>
|
||||
@@ -442,7 +442,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="lblDifficulty">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
@@ -455,7 +455,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="txtDifficulty">
|
||||
<property name="font">
|
||||
<font>
|
||||
@@ -474,7 +474,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="lblHashRate">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
@@ -487,7 +487,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="txtHashRate">
|
||||
<property name="font">
|
||||
<font>
|
||||
@@ -506,7 +506,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="lblTransactionCount">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
@@ -519,7 +519,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="txtTransactionCount">
|
||||
<property name="font">
|
||||
<font>
|
||||
@@ -538,6 +538,26 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="lblCoinFiatValue">
|
||||
<property name="text">
|
||||
<string>Coin Fiat Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="txtCoinFiatValue">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -40,6 +40,7 @@ class GUI20Skin : public QObject
|
||||
Q_PROPERTY( QColor colorTextActiveAutocomplete READ GetColorTextActiveAutocomplete CONSTANT )
|
||||
Q_PROPERTY( QColor colorTextDisabled READ GetColorTextDisabled CONSTANT )
|
||||
Q_PROPERTY( QColor colorTextDisabledAutocomplete READ GetColorTextDisabledAutocomplete CONSTANT )
|
||||
Q_PROPERTY( QColor colorTextBlack READ GetColorTextBlack CONSTANT )
|
||||
|
||||
Q_ENUMS( ESizeConstants )
|
||||
|
||||
@@ -80,6 +81,7 @@ public:
|
||||
const QColor GetColorTextActiveAutocomplete() const {return colorTextActiveAutocomplete;}
|
||||
const QColor GetColorTextDisabled() const {return colorTextDisabled;}
|
||||
const QColor GetColorTextDisabledAutocomplete() const {return colorTextDisabledAutocomplete;}
|
||||
const QColor GetColorTextBlack() const {return colorTextBlack;}
|
||||
|
||||
private:
|
||||
const QColor colorToolbarMainGradientBegin;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <QDateTime>
|
||||
#include "bitcoinunits.h"
|
||||
#include "main.h"
|
||||
|
||||
#include "overviewpage.h"
|
||||
#include "qtquick_controls/cpp/guiexchangeswidget.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -17,9 +17,8 @@ InfoPage::InfoPage(QWidget *parent) :
|
||||
exchangesWidget( 0 )
|
||||
{
|
||||
ui->setupUi(this);
|
||||
// ui->casinoInfoBox->setVisible(false);
|
||||
// ui->newsItemsBox->setVisible(false);
|
||||
|
||||
ui->coinInfoBox->setMinimumHeight(250);
|
||||
ui->exchangeInfoBox->setMinimumHeight(250);
|
||||
createExchangesWidget();
|
||||
}
|
||||
|
||||
@@ -119,3 +118,8 @@ void InfoPage::createExchangesWidget()
|
||||
exchangesWidget->slotPopulateExchangesFromWeb();
|
||||
ui->verticalLayoutExchanges->addWidget( exchangesWidget->dockQmlToWidget() );
|
||||
}
|
||||
|
||||
void InfoPage::setCoinFiatValue(QString coinValue)
|
||||
{
|
||||
ui->txtCoinFiatValue->setText(coinValue);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ public slots:
|
||||
void setNumBlocks(int count, int countOfPeers);
|
||||
/** Set number of transactions shown in the UI */
|
||||
void setNumTransactions(int count);
|
||||
/** Set Fiat coin value */
|
||||
void setCoinFiatValue(const QString coinValue);
|
||||
|
||||
public:
|
||||
explicit InfoPage(QWidget *parent = 0);
|
||||
|
||||
@@ -125,6 +125,7 @@ OverviewPage::OverviewPage(QWidget *parent) :
|
||||
ui->listTransactions->setItemDelegate(txdelegate);
|
||||
ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
|
||||
ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
|
||||
ui->listTransactions->setMinimumWidth(350);
|
||||
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
|
||||
connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex)));
|
||||
@@ -139,8 +140,13 @@ OverviewPage::OverviewPage(QWidget *parent) :
|
||||
// start with displaying the "out of sync" warnings
|
||||
showOutOfSyncWarning(true);
|
||||
|
||||
// get CoinInfo from the web
|
||||
// get CoinInfo on startup
|
||||
getCoinInfo();
|
||||
// start timer to get CoinInfo from the web every interval
|
||||
coinInfoRefreshTimer.setSingleShot( false );
|
||||
coinInfoRefreshTimer.setInterval( 1000 * 300 ); // every 5 minuts
|
||||
connect( &coinInfoRefreshTimer, SIGNAL( timeout() ), this, SLOT(getCoinInfo()), Qt::UniqueConnection );
|
||||
coinInfoRefreshTimer.start();
|
||||
}
|
||||
|
||||
void OverviewPage::handleTransactionClicked(const QModelIndex &index)
|
||||
@@ -272,8 +278,13 @@ void OverviewPage::updateFiatBalance(int currency)
|
||||
{
|
||||
QString conversionCurrency = QString("Price").append(Currencies::name(currency));
|
||||
double currencyValue = coinInformation.find(conversionCurrency).value().toDouble();
|
||||
// emit signal for change value
|
||||
QString coinValue = Currencies::format(currency, currencyValue, true, 4, false);
|
||||
emit coinFiatValueChanged(coinValue);
|
||||
// calculate and set fiat balance
|
||||
double fiatBalance = currentBalance * currencyValue;
|
||||
ui->labelBalanceFiat->setText(Currencies::format(currency,fiatBalance,true));
|
||||
QString fiatBalanceString = Currencies::format(currency,fiatBalance,true, 2, true);
|
||||
ui->labelBalanceFiat->setText(fiatBalanceString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <QWidget>
|
||||
#include <QJsonObject>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Ui {
|
||||
class OverviewPage;
|
||||
@@ -38,6 +39,7 @@ public slots:
|
||||
|
||||
signals:
|
||||
void transactionClicked(const QModelIndex &index);
|
||||
void coinFiatValueChanged(const QString formattedCoinFiatValue);
|
||||
|
||||
private:
|
||||
Ui::OverviewPage *ui;
|
||||
@@ -56,8 +58,8 @@ private:
|
||||
/** Get the CoinInfo from REST service */
|
||||
CasinoCoinWebAPIParser* cscWebApiParser;
|
||||
CasinoCoinWebAPI* cscWebApi;
|
||||
void getCoinInfo();
|
||||
QJsonObject coinInformation;
|
||||
QTimer coinInfoRefreshTimer;
|
||||
|
||||
private slots:
|
||||
void updateDisplayUnit();
|
||||
@@ -66,6 +68,7 @@ private slots:
|
||||
void updateCoinInfoFromWeb( JsonCoinInfoParser* coinInfoParser );
|
||||
void updateFiatBalance(int currency);
|
||||
void updateDisplayPromotions(bool checked);
|
||||
void getCoinInfo();
|
||||
};
|
||||
|
||||
#endif // OVERVIEWPAGE_H
|
||||
|
||||
@@ -83,7 +83,7 @@ QWidget* GUIExchangesWidget::dockQmlToWidget()
|
||||
pPlaceHolder = QWidget::createWindowContainer( pExchangesWindow, this );
|
||||
if ( pPlaceHolder )
|
||||
{
|
||||
pPlaceHolder->setMinimumSize( 500, 200 );
|
||||
pPlaceHolder->setMinimumSize( 500, 170 );
|
||||
pPlaceHolder->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,8 @@ WalletView::WalletView(QWidget *parent, BitcoinGUI *_gui):
|
||||
connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString)));
|
||||
// Clicking on "Export" allows to export the transaction list
|
||||
connect(exportButton, SIGNAL(clicked()), transactionView, SLOT(exportClicked()));
|
||||
|
||||
// subscribe to coin value changes
|
||||
connect(overviewPage, SIGNAL(coinFiatValueChanged(const QString)), infoPage, SLOT(setCoinFiatValue(const QString)));
|
||||
gotoOverviewPage();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,18 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "walletserver.h"
|
||||
#include "wallet.h"
|
||||
#include "walletdb.h"
|
||||
#include "bitcoinrpc.h"
|
||||
#include "init.h"
|
||||
#include "base58.h"
|
||||
#include "ui_interface.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
@@ -68,7 +74,7 @@ Value getinfo(const Array& params, bool fHelp)
|
||||
|
||||
proxyType proxy;
|
||||
GetProxy(NET_IPV4, proxy);
|
||||
|
||||
const Array emptyArray;
|
||||
Object obj;
|
||||
obj.push_back(Pair("version", (int)CLIENT_VERSION));
|
||||
obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
|
||||
@@ -77,6 +83,7 @@ Value getinfo(const Array& params, bool fHelp)
|
||||
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
|
||||
}
|
||||
obj.push_back(Pair("blocks", (int)nBestHeight));
|
||||
obj.push_back(Pair("coinsupply", ValueFromAmount(GetTotalCoinSupply(nBestHeight,false))));
|
||||
obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset()));
|
||||
obj.push_back(Pair("connections", (int)vNodes.size()));
|
||||
obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
|
||||
@@ -1626,3 +1633,209 @@ Value getcoinsupply(const Array& params, bool fHelp)
|
||||
int64 coinSupply = GetTotalCoinSupply(height,noCheckpoints);
|
||||
return ValueFromAmount(coinSupply);
|
||||
}
|
||||
|
||||
Value startwalletserversession(const Array ¶ms, bool fHelp)
|
||||
{
|
||||
if(!fWalletServer)
|
||||
throw runtime_error(
|
||||
"The server is not started in Wallet Server mode so no session can be created");
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"startwalletserversession [accountid]\n"
|
||||
"Starts a Wallet Server session and returns a session id.\n"
|
||||
"Pass in the [accountid] which will be used in future wallet server requests for the created session.");
|
||||
// get the account id
|
||||
std::string accountId = params[0].get_str();
|
||||
// check if accountId is not already in a session
|
||||
if(walletServer.isNewAccountId(accountId))
|
||||
{
|
||||
// Create a session id
|
||||
boost::uuids::uuid uuid = boost::uuids::random_generator()();
|
||||
std::string sessionId = boost::lexical_cast<std::string>(uuid);
|
||||
// create session object
|
||||
Session wsSession = {accountId, sessionId, (int)time(NULL), false, 0};
|
||||
// Notify the Wallet Server of the newsession
|
||||
walletServer.NotifyStartNewWalletServerSession(accountId, wsSession);
|
||||
Object ret;
|
||||
ret.push_back(Pair("accountid", accountId));
|
||||
ret.push_back(Pair("sessionid", sessionId));
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
throw JSONRPCError(RPC_WALLETSERVER_INVALID_ID, "Given identifier is already in an active session");
|
||||
|
||||
}
|
||||
|
||||
Value listwalletserversessions(const Array ¶ms, bool fHelp)
|
||||
{
|
||||
if(!fWalletServer)
|
||||
throw runtime_error(
|
||||
"The server is not started in Wallet Server mode so no sessions list available");
|
||||
if (fHelp || params.size() > 0)
|
||||
throw runtime_error(
|
||||
"listwalletserversessions\n"
|
||||
"Returns a list with current active walletserver sessions.");
|
||||
// get the sessions
|
||||
sessionKeyValueType &wsSessions = walletServer.getSessions();
|
||||
// create the output object
|
||||
Array ret;
|
||||
BOOST_FOREACH( sessionKeyValueType::value_type &session, wsSessions )
|
||||
{
|
||||
Object o;
|
||||
o.push_back(Pair("accountid", session.second.email));
|
||||
o.push_back(Pair("sessionid", session.second.sessionId));
|
||||
o.push_back(Pair("creationtime", session.second.creationTime));
|
||||
o.push_back(Pair("walletopen", session.second.walletOpen));
|
||||
o.push_back(Pair("lastcommandtime", session.second.lastCommandTime));
|
||||
ret.push_back(o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Value stopwalletserversession(const Array ¶ms, bool fHelp)
|
||||
{
|
||||
if(!fWalletServer)
|
||||
throw runtime_error(
|
||||
"The server is not started in Wallet Server mode so no sessions list available");
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"stopwalletserversession [sessionid]\n"
|
||||
"Removes a Wallet Server session and closes the wallet if open.\n"
|
||||
"Pass in the [sessionid] of the session that has to be removed.");
|
||||
// get the session id
|
||||
std::string sessionId = params[0].get_str();
|
||||
// remove session and return the result
|
||||
Object ret;
|
||||
ret.push_back(Pair("result", walletServer.deleteSession(sessionId)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
Value listwallets(const Array ¶ms, bool fHelp)
|
||||
{
|
||||
if(!fWalletServer)
|
||||
throw runtime_error(
|
||||
"The server is not started in Wallet Server mode so no wallet list available");
|
||||
if (fHelp || params.size() > 0)
|
||||
throw runtime_error(
|
||||
"listwallets\n"
|
||||
"Returns a list with wallets stored by the walletserver.");
|
||||
// get the wallets
|
||||
keyValueType wsWallets = walletServer.getWallets();
|
||||
// create the output object
|
||||
Array ret;
|
||||
BOOST_FOREACH( keyValueType::value_type &wallet, wsWallets )
|
||||
{
|
||||
Object o;
|
||||
o.push_back(Pair("walletid", wallet.first));
|
||||
o.push_back(Pair("accountid", wallet.second));
|
||||
ret.push_back(o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Value wsopenwallet(const Array ¶ms, bool fHelp)
|
||||
{
|
||||
if(!fWalletServer)
|
||||
throw runtime_error(
|
||||
"The server is not started in Wallet Server mode so command is not available");
|
||||
if (fHelp || params.size() != 3)
|
||||
throw runtime_error(
|
||||
"wsopenwallet [sessionid] [accountid] [walletid]\n"
|
||||
"Open a wallet for a session. account and wallet id combination.");
|
||||
// get the wallets
|
||||
keyValueType wsWallets = walletServer.getWallets();
|
||||
// create the output object
|
||||
Array ret;
|
||||
BOOST_FOREACH( keyValueType::value_type &wallet, wsWallets )
|
||||
{
|
||||
Object o;
|
||||
o.push_back(Pair("walletid", wallet.first));
|
||||
o.push_back(Pair("accountid", wallet.second));
|
||||
ret.push_back(o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Value wsclosewallet(const Array ¶ms, bool fHelp)
|
||||
{
|
||||
if(!fWalletServer)
|
||||
throw runtime_error(
|
||||
"The server is not started in Wallet Server mode so command is not available");
|
||||
if (fHelp || params.size() != 3)
|
||||
throw runtime_error(
|
||||
"wsclosewallet [sessionid] [accountid] [walletid]\n"
|
||||
"Open a wallet for a session. account and wallet id combination.");
|
||||
// get the wallets
|
||||
keyValueType wsWallets = walletServer.getWallets();
|
||||
// create the output object
|
||||
Array ret;
|
||||
BOOST_FOREACH( keyValueType::value_type &wallet, wsWallets )
|
||||
{
|
||||
Object o;
|
||||
o.push_back(Pair("walletid", wallet.first));
|
||||
o.push_back(Pair("accountid", wallet.second));
|
||||
ret.push_back(o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Value wsgetinfo(const Array ¶ms, bool fHelp)
|
||||
{
|
||||
if(!fWalletServer)
|
||||
throw runtime_error(
|
||||
"The server is not started in Wallet Server mode so command is not available");
|
||||
if (fHelp || params.size() != 3)
|
||||
throw runtime_error(
|
||||
"wsgetinfo [sessionid] [accountid] [walletid]\n"
|
||||
"Get the Wallet Information for a given session. account and wallet id combination.");
|
||||
Object obj;
|
||||
obj.push_back(Pair("version", (int)CLIENT_VERSION));
|
||||
obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
|
||||
return obj;
|
||||
}
|
||||
|
||||
Value wsgetaddresslist(const Array ¶ms, bool fHelp)
|
||||
{
|
||||
if(!fWalletServer)
|
||||
throw runtime_error(
|
||||
"The server is not started in Wallet Server mode so command is not available");
|
||||
if (fHelp || params.size() != 3)
|
||||
throw runtime_error(
|
||||
"wsgetaddresslist [sessionid] [accountid] [walletid]\n"
|
||||
"Open a wallet for a session. account and wallet id combination.");
|
||||
// get the wallets
|
||||
keyValueType wsWallets = walletServer.getWallets();
|
||||
// create the output object
|
||||
Array ret;
|
||||
BOOST_FOREACH( keyValueType::value_type &wallet, wsWallets )
|
||||
{
|
||||
Object o;
|
||||
o.push_back(Pair("walletid", wallet.first));
|
||||
o.push_back(Pair("accountid", wallet.second));
|
||||
ret.push_back(o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Value wssendtoaddress(const Array ¶ms, bool fHelp)
|
||||
{
|
||||
if(!fWalletServer)
|
||||
throw runtime_error(
|
||||
"The server is not started in Wallet Server mode so command is not available");
|
||||
if (fHelp || params.size() != 5)
|
||||
throw runtime_error(
|
||||
"wssendtoaddress [sessionid] [accountid] [walletid] [address] [amount]\n"
|
||||
"Open a wallet for a session. account and wallet id combination.");
|
||||
// get the wallets
|
||||
keyValueType wsWallets = walletServer.getWallets();
|
||||
// create the output object
|
||||
Array ret;
|
||||
BOOST_FOREACH( keyValueType::value_type &wallet, wsWallets )
|
||||
{
|
||||
Object o;
|
||||
o.push_back(Pair("walletid", wallet.first));
|
||||
o.push_back(Pair("accountid", wallet.second));
|
||||
ret.push_back(o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
601
src/stomp/booststomp.cpp
Normal file
601
src/stomp/booststomp.cpp
Normal file
@@ -0,0 +1,601 @@
|
||||
/*
|
||||
BoostStomp - a STOMP (Simple Text Oriented Messaging Protocol) client
|
||||
----------------------------------------------------
|
||||
Copyright (c) 2012 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
||||
|
||||
SOFTWARE NOTICE AND LICENSE
|
||||
|
||||
BoostStomp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
BoostStomp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with BoostStomp. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
for more information on the LGPL, see:
|
||||
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
||||
*/
|
||||
|
||||
// based on the ASIO async TCP client example found on Boost documentation:
|
||||
// http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio/example/timeouts/async_tcp_client.cpp
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "booststomp.h"
|
||||
#include "main.h"
|
||||
|
||||
namespace STOMP {
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
using namespace boost::asio;
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
// used by debug_print
|
||||
boost::mutex global_stream_lock;
|
||||
|
||||
// ----------------------------
|
||||
// constructor
|
||||
// ----------------------------
|
||||
BoostStomp::BoostStomp(string& hostname, int& port, AckMode ackmode /*= ACK_AUTO*/):
|
||||
// ----------------------------
|
||||
// protected members setup
|
||||
//m_sendqueue (new std::queue<Frame*>()),
|
||||
//m_sendqueue_mutex (new boost::mutex()),
|
||||
m_hostname (hostname),
|
||||
m_port (port),
|
||||
m_ackmode (ackmode),
|
||||
m_stopped (true),
|
||||
m_connected (false),
|
||||
m_io_service (new io_service()),
|
||||
m_io_service_work (new io_service::work(*m_io_service)),
|
||||
m_strand (new io_service::strand(*m_io_service)),
|
||||
m_socket (new tcp::socket(*m_io_service)),
|
||||
// private members
|
||||
m_protocol_version("1.0"),
|
||||
m_transaction_id(0)
|
||||
// ----------------------------
|
||||
{
|
||||
// map STOMP server commands to handler methods
|
||||
cmd_map["CONNECTED"] = &BoostStomp::process_CONNECTED;
|
||||
cmd_map["MESSAGE"] = &BoostStomp::process_MESSAGE;
|
||||
cmd_map["RECEIPT"] = &BoostStomp::process_RECEIPT;
|
||||
cmd_map["ERROR"] = &BoostStomp::process_ERROR;
|
||||
// set default debug flag
|
||||
m_showDebug = false;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------
|
||||
// destructor
|
||||
// ----------------------------
|
||||
BoostStomp::~BoostStomp()
|
||||
// ----------------------------
|
||||
{
|
||||
// first stop io_service so as to exit the run loop (when idle)
|
||||
m_io_service->stop();
|
||||
// then interrupt the worker thread
|
||||
worker_thread->interrupt();
|
||||
// delete m_heartbeat_timer; // no need, its a shared_ptr
|
||||
delete worker_thread;
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// worker thread
|
||||
// ----------------------------
|
||||
void BoostStomp::worker( boost::shared_ptr< boost::asio::io_service > _io_service )
|
||||
{
|
||||
debug_print("Worker thread: starting...");
|
||||
while(!m_stopped) {
|
||||
_io_service->run();
|
||||
debug_print("Worker thread: io_service is stopped...");
|
||||
_io_service->reset();
|
||||
boost::this_thread::sleep_for( boost::chrono::seconds(1));
|
||||
}
|
||||
debug_print("Worker thread finished.");
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------
|
||||
// ASIO HANDLERS (protected)
|
||||
// ----------------------------
|
||||
|
||||
|
||||
// Called by the user of the client class to initiate the connection process.
|
||||
// The endpoint iterator will have been obtained using a tcp::resolver.
|
||||
void BoostStomp::start(string& login, string& passcode)
|
||||
{
|
||||
debug_print("starting...");
|
||||
m_stopped = false;
|
||||
tcp::resolver resolver(*m_io_service);
|
||||
tcp::resolver::iterator endpoint_iter = resolver.resolve(tcp::resolver::query(
|
||||
m_hostname,
|
||||
to_string<int>(m_port, std::dec),
|
||||
boost::asio::ip::resolver_query_base::numeric_service)
|
||||
);
|
||||
// Start the connect actor.
|
||||
start_connect(endpoint_iter, login, passcode);
|
||||
}
|
||||
|
||||
void BoostStomp::start()
|
||||
{
|
||||
std::string empty = "";
|
||||
start(empty, empty);
|
||||
}
|
||||
|
||||
// This function terminates all the actors to shut down the connection. It
|
||||
// may be called by the user of the client class, or by the class itself in
|
||||
// response to graceful termination or an unrecoverable error.
|
||||
void BoostStomp::stop()
|
||||
{
|
||||
debug_print("stopping...");
|
||||
if (m_connected && m_socket->is_open()) {
|
||||
Frame frame( "DISCONNECT");
|
||||
frame.encode(stomp_request);
|
||||
debug_print("Sending DISCONNECT frame...");
|
||||
boost::asio::write(*m_socket, stomp_request);
|
||||
}
|
||||
m_connected = false;
|
||||
m_stopped = true;
|
||||
if (m_heartbeat_timer != NULL) {
|
||||
m_heartbeat_timer->cancel();
|
||||
}
|
||||
//
|
||||
m_socket->close();
|
||||
//
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// --------------------------------------------------
|
||||
// ---------- TCP CONNECTION SETUP ------------------
|
||||
// --------------------------------------------------
|
||||
|
||||
// --------------------------------------------------
|
||||
void BoostStomp::start_connect(tcp::resolver::iterator endpoint_iter, string& login, string& passcode)
|
||||
// --------------------------------------------------
|
||||
{
|
||||
if (endpoint_iter != tcp::resolver::iterator())
|
||||
{
|
||||
debug_print(boost::format("STOMP: Connecting to %1%...") % endpoint_iter->endpoint() );
|
||||
|
||||
// Try TCP connection synchronously (the first frame to send is the CONNECT frame)
|
||||
boost::system::error_code ec;
|
||||
m_socket->connect(endpoint_iter->endpoint(), ec);
|
||||
if (!ec) {
|
||||
// now we are connected to STOMP server's TCP port/
|
||||
debug_print(boost::format("STOMP TCP connection to %1% is active") % endpoint_iter->endpoint() );
|
||||
|
||||
// Send the CONNECT request synchronously (immediately).
|
||||
hdrmap headers;
|
||||
headers["accept-version"] = "1.1";
|
||||
headers["host"] = m_hostname;
|
||||
if (!login.empty()) {
|
||||
headers["login"] = login;
|
||||
headers["passcode"] = passcode;
|
||||
}
|
||||
Frame frame( "CONNECT", headers );
|
||||
frame.encode(stomp_request);
|
||||
debug_print("Sending CONNECT frame...");
|
||||
boost::asio::write(*m_socket, stomp_request);
|
||||
// start the read actor so as to receive the CONNECTED frame
|
||||
start_stomp_read_headers();
|
||||
// start worker thread (m_io_service.run())
|
||||
worker_thread = new boost::thread( boost::bind( &BoostStomp::worker, this, m_io_service ) );
|
||||
} else {
|
||||
// We need to close the socket used in the previous connection attempt
|
||||
// before starting a new one.
|
||||
m_socket->close();
|
||||
// Try the next available endpoint.
|
||||
start_connect(++endpoint_iter, login, passcode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are no more endpoints to try.
|
||||
stop();
|
||||
debug_print("Connection unsuccessful. Sleeping, then retrying...");
|
||||
boost::this_thread::sleep_for( boost::chrono::seconds(3));
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
// ---------- INPUT ACTOR SETUP ------------------
|
||||
// -----------------------------------------------
|
||||
|
||||
// -----------------------------------------------
|
||||
void BoostStomp::start_stomp_read_headers()
|
||||
// -----------------------------------------------
|
||||
{
|
||||
debug_print("start_stomp_read_headers");
|
||||
// Start an asynchronous operation to read at least the STOMP frame command & headers (till the double newline delimiter)
|
||||
boost::asio::async_read_until(
|
||||
*m_socket,
|
||||
stomp_response,
|
||||
"\n\n",
|
||||
boost::bind(&BoostStomp::handle_stomp_read_headers, this, placeholders::error()));
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
void BoostStomp::handle_stomp_read_headers(const boost::system::error_code& ec)
|
||||
// -----------------------------------------------
|
||||
{
|
||||
if (m_stopped)
|
||||
return;
|
||||
|
||||
if (!ec)
|
||||
{
|
||||
std::size_t bodysize = 0;
|
||||
try {
|
||||
debug_print("handle_stomp_read_headers");
|
||||
m_rcvd_frame = new Frame(stomp_response, cmd_map); // freed by consume_frame
|
||||
hdrmap& _headers = m_rcvd_frame->headers();
|
||||
// if the frame headers contain 'content-length', use that to call the proper async_read overload
|
||||
if (_headers.find("content-length") != _headers.end()) {
|
||||
string& content_length = _headers["content-length"];
|
||||
debug_print(boost::format("received response (command+headers: %1% bytes, content-length: %2%)") % stomp_response.size() % content_length );
|
||||
bodysize = lexical_cast<size_t>(content_length);
|
||||
}
|
||||
start_stomp_read_body(bodysize);
|
||||
} catch(NoMoreFrames&) {
|
||||
debug_print("No more frames!");
|
||||
// break;
|
||||
} catch(std::exception& e) {
|
||||
debug_print(boost::format("handle_stomp_read in loop: unknown exception in Frame constructor:\n%1%") % e.what());
|
||||
exit(10);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "BoostStomp: Error on receive: " << ec.message() << "\n";
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
void BoostStomp::start_stomp_read_body(std::size_t bodysize)
|
||||
// -----------------------------------------------
|
||||
{
|
||||
debug_print("start_stomp_read_body");
|
||||
// Start an asynchronous operation to read at least the STOMP frame body
|
||||
if (bodysize == 0) {
|
||||
boost::asio::async_read_until(
|
||||
*m_socket, stomp_response,
|
||||
'\0', // NULL signifies the end of the body
|
||||
boost::bind(&BoostStomp::handle_stomp_read_body, this, placeholders::error(), placeholders::bytes_transferred()));
|
||||
} else {
|
||||
boost::asio::async_read(
|
||||
*m_socket, stomp_response,
|
||||
boost::asio::transfer_at_least(bodysize),
|
||||
boost::bind(&BoostStomp::handle_stomp_read_body, this, placeholders::error(), placeholders::bytes_transferred()));
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
void BoostStomp::handle_stomp_read_body(const boost::system::error_code& ec, std::size_t bytes_transferred = 0)
|
||||
// -----------------------------------------------
|
||||
{
|
||||
if (m_stopped)
|
||||
return;
|
||||
|
||||
if (!ec)
|
||||
{
|
||||
debug_print(boost::format("received response (%1% bytes) (buffer: %2% bytes)") % bytes_transferred % stomp_response.size() );
|
||||
if (m_rcvd_frame != NULL) {
|
||||
m_rcvd_frame->parse_body(stomp_response);
|
||||
consume_received_frame();
|
||||
}
|
||||
//
|
||||
//debug_print("stomp_response contents after Frame scanning:");
|
||||
//hexdump(stomp_response);
|
||||
|
||||
// wait for the next incoming frame from the server...
|
||||
start_stomp_read_headers();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "BoostStomp: Error on receive: " << ec.message() << "\n";
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
void BoostStomp::consume_received_frame()
|
||||
// ------------------------------------------
|
||||
{
|
||||
if (m_rcvd_frame != NULL) {
|
||||
// is there a declared handler for the command in the received STOMP frame?
|
||||
if (pfnStompCommandHandler_t handler = cmd_map[m_rcvd_frame->command()]) {
|
||||
debug_print(boost::format("-- consume_frame: calling %1% command handler") % m_rcvd_frame->command());
|
||||
// call STOMP command handler
|
||||
(this->*handler)();
|
||||
}
|
||||
delete m_rcvd_frame;
|
||||
}
|
||||
m_rcvd_frame = NULL;
|
||||
};
|
||||
|
||||
// ------------------------------------------------
|
||||
// ---------- OUTPUT ACTOR SETUP ------------------
|
||||
// ------------------------------------------------
|
||||
|
||||
// -----------------------------------------------
|
||||
void BoostStomp::start_stomp_write()
|
||||
// -----------------------------------------------
|
||||
{
|
||||
if ((m_stopped) || (!m_connected))
|
||||
return;
|
||||
|
||||
//debug_print("start_stomp_write");
|
||||
Frame* frame = NULL;
|
||||
|
||||
// send all STOMP frames in queue
|
||||
while (m_sendqueue.try_pop(frame)) {
|
||||
debug_print(boost::format("Sending %1% frame...") % frame->command() );
|
||||
frame->encode(stomp_request);
|
||||
try {
|
||||
boost::asio::write(
|
||||
*m_socket,
|
||||
stomp_request
|
||||
);
|
||||
debug_print("Sent!");
|
||||
delete frame;
|
||||
} catch (boost::system::system_error& err){
|
||||
m_connected = false;
|
||||
debug_print(boost::format("Error writing to STOMP server: error code:%1%, message:%2%") % err.code() % err.what());
|
||||
// put! the kot! down! slowly!
|
||||
if(err.code().value() != 10009)
|
||||
m_sendqueue.push(frame);
|
||||
stop();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
void BoostStomp::start_stomp_heartbeat()
|
||||
// -----------------------------------------------
|
||||
{
|
||||
// Start an asynchronous operation to send a heartbeat message.
|
||||
//debug_print("Sending heartbeat...");
|
||||
boost::asio::async_write(
|
||||
*m_socket,
|
||||
m_heartbeat,
|
||||
boost::bind(&BoostStomp::handle_stomp_heartbeat, this, _1)
|
||||
);
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
void BoostStomp::handle_stomp_heartbeat(const boost::system::error_code& ec)
|
||||
// -----------------------------------------------
|
||||
{
|
||||
if (m_stopped)
|
||||
return;
|
||||
|
||||
if (!ec)
|
||||
{
|
||||
// Wait 10 seconds before sending the next heartbeat.
|
||||
m_heartbeat_timer->expires_from_now(boost::posix_time::seconds(10));
|
||||
m_heartbeat_timer->async_wait(
|
||||
boost::bind(
|
||||
&BoostStomp::start_stomp_heartbeat,
|
||||
this
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Error on sending heartbeat: " << ec.message() << "\n";
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------
|
||||
void BoostStomp::process_CONNECTED()
|
||||
//-----------------------------------------
|
||||
{
|
||||
m_connected = true;
|
||||
// try to get supported protocol version from headers
|
||||
hdrmap _headers = m_rcvd_frame->headers();
|
||||
if (_headers.find("version") != _headers.end()) {
|
||||
m_protocol_version = _headers["version"];
|
||||
debug_print(boost::format("server supports STOMP version %1%") % m_protocol_version);
|
||||
}
|
||||
if (m_protocol_version == "1.1") {
|
||||
// we are connected to a version 1.1 STOMP server, setup heartbeat
|
||||
m_heartbeat_timer = boost::shared_ptr< deadline_timer> ( new deadline_timer( *m_io_service ));
|
||||
std::ostream os( &m_heartbeat);
|
||||
os << "\n";
|
||||
// we can start the heartbeat actor
|
||||
start_stomp_heartbeat();
|
||||
}
|
||||
// in case of reconnection, we need to re-subscribe to all subscriptions
|
||||
for (subscription_map::iterator it = m_subscriptions.begin(); it != m_subscriptions.end(); it++) {
|
||||
//string topic = (*it).first;
|
||||
do_subscribe((*it).first);
|
||||
};
|
||||
}
|
||||
|
||||
//-----------------------------------------
|
||||
void BoostStomp::process_MESSAGE()
|
||||
//-----------------------------------------
|
||||
{
|
||||
bool acked = true;
|
||||
hdrmap& _headers = m_rcvd_frame->headers();
|
||||
if (_headers.find("destination") != _headers.end()) {
|
||||
string& dest = _headers["destination"];
|
||||
//
|
||||
if (pfnOnStompMessage_t callback_function = m_subscriptions[dest]) {
|
||||
//debug_print(boost::format("-- consume_frame: firing callback for %1%") % dest);
|
||||
//
|
||||
acked = callback_function(m_rcvd_frame);
|
||||
};
|
||||
};
|
||||
// acknowledge frame, if in "Client" or "Client-Individual" ack mode
|
||||
if ((m_ackmode == ACK_CLIENT) || (m_ackmode == ACK_CLIENT_INDIVIDUAL)) {
|
||||
acknowledge(m_rcvd_frame, acked);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------
|
||||
void BoostStomp::process_RECEIPT()
|
||||
//-----------------------------------------
|
||||
{
|
||||
hdrmap& _headers = m_rcvd_frame->headers();
|
||||
if (_headers.find("receipt_id") != _headers.end()) {
|
||||
string& receipt_id = _headers["receipt_id"];
|
||||
// do something with receipt...
|
||||
debug_print(boost::format("receipt-id == %1%") % receipt_id);
|
||||
};
|
||||
}
|
||||
|
||||
//-----------------------------------------
|
||||
void BoostStomp::process_ERROR()
|
||||
//-----------------------------------------
|
||||
{
|
||||
hdrmap& _headers = m_rcvd_frame->headers();
|
||||
string errormessage = (_headers.find("message") != _headers.end()) ?
|
||||
_headers["message"] :
|
||||
"(unknown error!)";
|
||||
errormessage += m_rcvd_frame->body().c_str();
|
||||
//throw(errormessage);
|
||||
cerr << endl << "============= BoostStomp got an ERROR frame from server: =================" << endl << errormessage << endl;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------
|
||||
bool BoostStomp::send_frame( Frame* frame )
|
||||
//-----------------------------------------
|
||||
{
|
||||
// send_frame is called from the application thread. Do not dereference frame here!!! (shared data)
|
||||
//debug_print(boost::format("send_frame: Adding frame to send queue...") % frame->command() );
|
||||
//debug_print("send_frame: Adding frame to send queue...");
|
||||
m_sendqueue.push(frame); // concurrent_queue does all the thread safety stuff
|
||||
// tell io_service to start the output actor so as the frame get sent from the worker thread
|
||||
m_strand->post(
|
||||
boost::bind(&BoostStomp::start_stomp_write, this)
|
||||
);
|
||||
return(true);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// ------------------------ PUBLIC INTERFACE ------------------------
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ------------------------------------------
|
||||
bool BoostStomp::subscribe( string& topic, pfnOnStompMessage_t callback )
|
||||
// ------------------------------------------
|
||||
{
|
||||
debug_print(boost::format("Setting callback function for %1%") % topic);
|
||||
m_subscriptions[topic] = callback;
|
||||
return(do_subscribe(topic));
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
bool BoostStomp::do_subscribe(const string& topic)
|
||||
// ------------------------------------------
|
||||
{
|
||||
hdrmap hm;
|
||||
hm["id"] = lexical_cast<string>(boost::this_thread::get_id());
|
||||
hm["destination"] = topic;
|
||||
return(send_frame(new Frame( "SUBSCRIBE", hm )));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------
|
||||
bool BoostStomp::unsubscribe( string& topic )
|
||||
// ------------------------------------------
|
||||
{
|
||||
hdrmap hm;
|
||||
hm["destination"] = topic;
|
||||
m_subscriptions.erase(topic);
|
||||
return(send_frame(new Frame( "UNSUBSCRIBE", hm )));
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
bool BoostStomp::acknowledge(Frame* frame, bool acked = true)
|
||||
// ------------------------------------------
|
||||
{
|
||||
hdrmap hm = frame->headers();
|
||||
string _ack_cmd = (acked ? "ACK" : "NACK");
|
||||
return(send_frame(new Frame( _ack_cmd, hm )));
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
int BoostStomp::begin()
|
||||
// ------------------------------------------
|
||||
// returns a new transaction id
|
||||
{
|
||||
hdrmap hm;
|
||||
// create a new transaction id
|
||||
hm["transaction"] = lexical_cast<string>(m_transaction_id++);
|
||||
Frame* frame = new Frame( "BEGIN", hm );
|
||||
send_frame(frame);
|
||||
return(m_transaction_id);
|
||||
};
|
||||
|
||||
// ------------------------------------------
|
||||
bool BoostStomp::commit(int transaction_id)
|
||||
// ------------------------------------------
|
||||
{
|
||||
hdrmap hm;
|
||||
// add required header
|
||||
hm["transaction"] = lexical_cast<string>(transaction_id);
|
||||
return(send_frame(new Frame( "COMMIT", hm )));
|
||||
};
|
||||
|
||||
// ------------------------------------------
|
||||
bool BoostStomp::abort(int transaction_id)
|
||||
// ------------------------------------------
|
||||
{
|
||||
hdrmap hm;
|
||||
// add required header
|
||||
hm["transaction"] = lexical_cast<string>(transaction_id);
|
||||
return(send_frame(new Frame( "ABORT", hm )));
|
||||
};
|
||||
|
||||
// ------------------------------------------
|
||||
void BoostStomp::enable_debug_msgs(bool b)
|
||||
// ------------------------------------------
|
||||
{
|
||||
m_showDebug = b;
|
||||
}
|
||||
|
||||
void BoostStomp::debug_print(string& str) {
|
||||
boost::format fmt = boost::format(str.c_str());
|
||||
debug_print(fmt);
|
||||
}
|
||||
|
||||
void BoostStomp::debug_print(const char* cstr) {
|
||||
boost::format fmt = boost::format(cstr);
|
||||
BoostStomp::debug_print(fmt);
|
||||
}
|
||||
|
||||
void BoostStomp::debug_print(boost::format& fmt) {
|
||||
using namespace boost::posix_time;
|
||||
if (m_showDebug) {
|
||||
ptime now = second_clock::universal_time();
|
||||
global_stream_lock.lock();
|
||||
printf("[%s: %s] BoostStomp: %s\n", FormatTime(now).c_str(), boost::lexical_cast<std::string>(boost::this_thread::get_id()).c_str(), fmt.str().c_str());
|
||||
global_stream_lock.unlock();
|
||||
}
|
||||
}
|
||||
} // end namespace STOMP
|
||||
181
src/stomp/booststomp.h
Normal file
181
src/stomp/booststomp.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
BoostStomp - a STOMP (Simple Text Oriented Messaging Protocol) client using BOOST (http://www.boost.org)
|
||||
----------------------------------------------------
|
||||
Copyright (c) 2012 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
||||
|
||||
SOFTWARE NOTICE AND LICENSE
|
||||
|
||||
BoostStomp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Thrift4OZW is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with BoostStomp. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
for more information on the LGPL, see:
|
||||
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
||||
*/
|
||||
|
||||
// booststomp.h
|
||||
//
|
||||
|
||||
#ifndef __BOOSTSTOMP_H_
|
||||
#define __BOOSTSTOMP_H_
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
//#include <queue>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include "stompframe.h"
|
||||
#include "helpers.h"
|
||||
|
||||
|
||||
namespace STOMP {
|
||||
|
||||
using namespace boost;
|
||||
using namespace boost::asio;
|
||||
using namespace boost::asio::ip;
|
||||
|
||||
// ACK mode
|
||||
typedef enum {
|
||||
ACK_AUTO=0, // implicit acknowledgment (no ACK is sent)
|
||||
ACK_CLIENT, // explicit acknowledgment (must ACK)
|
||||
ACK_CLIENT_INDIVIDUAL //
|
||||
} AckMode;
|
||||
|
||||
// Stomp message callback function prototype
|
||||
typedef bool (*pfnOnStompMessage_t)( Frame* );
|
||||
|
||||
// Stomp subscription map (topic => callback)
|
||||
typedef std::map<std::string, pfnOnStompMessage_t> subscription_map;
|
||||
|
||||
// here we go
|
||||
// -------------
|
||||
class BoostStomp
|
||||
// -------------
|
||||
{
|
||||
//----------------
|
||||
protected:
|
||||
//----------------
|
||||
Frame* m_rcvd_frame;
|
||||
//boost::shared_ptr< std::queue<Frame*> > m_sendqueue;
|
||||
//boost::shared_ptr< boost::mutex > m_sendqueue_mutex;
|
||||
concurrent_queue<Frame*> m_sendqueue;
|
||||
subscription_map m_subscriptions;
|
||||
//
|
||||
std::string m_hostname;
|
||||
int m_port;
|
||||
AckMode m_ackmode;
|
||||
//
|
||||
bool m_stopped;
|
||||
bool m_connected; // have we completed application-level STOMP connection?
|
||||
|
||||
boost::shared_ptr< io_service > m_io_service;
|
||||
boost::shared_ptr< io_service::work > m_io_service_work;
|
||||
boost::shared_ptr< io_service::strand> m_strand;
|
||||
tcp::socket* m_socket;
|
||||
|
||||
|
||||
|
||||
boost::asio::streambuf stomp_request, stomp_response;
|
||||
//----------------
|
||||
private:
|
||||
//----------------
|
||||
boost::mutex stream_mutex;
|
||||
boost::thread* worker_thread;
|
||||
boost::shared_ptr<deadline_timer> m_heartbeat_timer;
|
||||
boost::asio::streambuf m_heartbeat;
|
||||
string m_protocol_version;
|
||||
int m_transaction_id;
|
||||
bool m_showDebug;
|
||||
|
||||
//
|
||||
bool send_frame( Frame* _frame );
|
||||
bool do_subscribe (const string& topic);
|
||||
//
|
||||
void consume_received_frame();
|
||||
void process_CONNECTED();
|
||||
void process_MESSAGE();
|
||||
void process_RECEIPT();
|
||||
void process_ERROR();
|
||||
|
||||
void start_connect(tcp::resolver::iterator endpoint_iter, string& login, string& passcode);
|
||||
void handle_connect(const boost::system::error_code& ec, tcp::resolver::iterator endpoint_iter);
|
||||
|
||||
//TODO: void setup_stomp_heartbeat(int cx, int cy);
|
||||
|
||||
void start_stomp_heartbeat();
|
||||
void handle_stomp_heartbeat(const boost::system::error_code& ec);
|
||||
|
||||
void start_stomp_read_headers();
|
||||
void handle_stomp_read_headers(const boost::system::error_code& ec);
|
||||
void start_stomp_read_body(std::size_t);
|
||||
void handle_stomp_read_body(const boost::system::error_code& ec, std::size_t bytes_transferred);
|
||||
|
||||
void start_stomp_write();
|
||||
//void handle_stomp_write(const boost::system::error_code& ec);
|
||||
|
||||
void worker( boost::shared_ptr< boost::asio::io_service > io_service );
|
||||
|
||||
void debug_print(boost::format& fmt);
|
||||
void debug_print(string& str);
|
||||
void debug_print(const char* str);
|
||||
|
||||
//----------------
|
||||
public:
|
||||
//----------------
|
||||
// constructor
|
||||
BoostStomp(string& hostname, int& port, AckMode ackmode = ACK_AUTO);
|
||||
// destructor
|
||||
~BoostStomp();
|
||||
|
||||
stomp_server_command_map_t cmd_map;
|
||||
|
||||
void start();
|
||||
void start(string& login, string& passcode);
|
||||
void stop();
|
||||
|
||||
// Set or clear the debug flag
|
||||
void enable_debug_msgs(bool b);
|
||||
|
||||
// thread-safe methods called from outside the thread loop
|
||||
template <typename BodyType>
|
||||
bool send ( std::string& _topic, hdrmap _headers, BodyType& _body, pfnOnStompMessage_t callback = NULL) {
|
||||
_headers["destination"] = _topic;
|
||||
Frame* frame = new Frame( "SEND", _headers, _body );
|
||||
return(send_frame(frame));
|
||||
}
|
||||
|
||||
//bool send ( std::string& topic, hdrmap _headers, std::string& body );
|
||||
//
|
||||
bool subscribe ( std::string& topic, pfnOnStompMessage_t callback );
|
||||
bool unsubscribe ( std::string& topic );
|
||||
bool acknowledge ( Frame* _frame, bool acked );
|
||||
|
||||
// STOMP transactions
|
||||
int begin(); // returns a new transaction id
|
||||
bool commit(int transaction_id);
|
||||
bool abort(int transaction_id);
|
||||
//
|
||||
AckMode get_ackmode() { return m_ackmode; };
|
||||
//
|
||||
}; //class
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
45
src/stomp/helpers.cpp
Normal file
45
src/stomp/helpers.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* helpers.cpp
|
||||
*
|
||||
* Created on: 22 Απρ 2012
|
||||
* Author: ekarak
|
||||
*/
|
||||
|
||||
|
||||
#include "helpers.h"
|
||||
#include <iostream>
|
||||
|
||||
void hexdump(const void *ptr, int buflen) {
|
||||
unsigned char *buf = (unsigned char*)ptr;
|
||||
int i, j;
|
||||
for (i=0; i<buflen; i+=16) {
|
||||
printf("%06x: ", i);
|
||||
for (j=0; j<16; j++)
|
||||
if (i+j < buflen)
|
||||
printf("%02x ", buf[i+j]);
|
||||
else
|
||||
printf(" ");
|
||||
printf(" ");
|
||||
for (j=0; j<16; j++)
|
||||
if (i+j < buflen)
|
||||
printf("%c", isprint(buf[i+j]) ? buf[i+j] : '.');
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void hexdump(boost::asio::streambuf& sb) {
|
||||
const char* rawdata = boost::asio::buffer_cast<const char*>(sb.data());
|
||||
hexdump(rawdata, sb.size());
|
||||
}
|
||||
|
||||
std::string FormatTime(boost::posix_time::ptime& now)
|
||||
{
|
||||
using namespace boost::posix_time;
|
||||
static std::locale loc(std::wcout.getloc(),
|
||||
new time_facet("%H:%M:%S"));
|
||||
|
||||
std::basic_stringstream<char> ss;
|
||||
ss.imbue(loc);
|
||||
ss << now;
|
||||
return ss.str();
|
||||
}
|
||||
91
src/stomp/helpers.h
Normal file
91
src/stomp/helpers.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* helpers.h
|
||||
*
|
||||
* Created on: 22 Απρ 2012
|
||||
* Author: ekarak
|
||||
*/
|
||||
|
||||
#ifndef HELPERS_H_
|
||||
#define HELPERS_H_
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// helper function
|
||||
void hexdump(boost::asio::streambuf&);
|
||||
void hexdump(const void *ptr, int buflen);
|
||||
|
||||
std::string FormatTime(boost::posix_time::ptime&);
|
||||
|
||||
// helper template function for pretty-printing just about anything
|
||||
template <class T>
|
||||
std::string to_string(T t, std::ios_base & (*f)(std::ios_base&))
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss.setf (std::ios_base::showbase);
|
||||
oss << f << t;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Concurrent queue, courtesy of:
|
||||
// http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
|
||||
// -------------------------------
|
||||
template<typename Data>
|
||||
class concurrent_queue
|
||||
{
|
||||
private:
|
||||
std::queue<Data> the_queue;
|
||||
mutable boost::mutex the_mutex;
|
||||
boost::condition_variable the_condition_variable;
|
||||
public:
|
||||
void push(Data const& data)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(the_mutex);
|
||||
the_queue.push(data);
|
||||
lock.unlock();
|
||||
the_condition_variable.notify_one();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(the_mutex);
|
||||
return the_queue.empty();
|
||||
}
|
||||
|
||||
bool try_pop(Data& popped_value)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(the_mutex);
|
||||
if(the_queue.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
popped_value=the_queue.front();
|
||||
the_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
void wait_and_pop(Data& popped_value)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(the_mutex);
|
||||
while(the_queue.empty())
|
||||
{
|
||||
the_condition_variable.wait(lock);
|
||||
}
|
||||
|
||||
popped_value=the_queue.front();
|
||||
the_queue.pop();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* HELPERS_H_ */
|
||||
196
src/stomp/stompframe.cpp
Normal file
196
src/stomp/stompframe.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
BoostStomp - a STOMP (Simple Text Oriented Messaging Protocol) client
|
||||
----------------------------------------------------
|
||||
Copyright (c) 2012 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
||||
|
||||
SOFTWARE NOTICE AND LICENSE
|
||||
|
||||
BoostStomp is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
BoostStomp is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with BoostStomp. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
for more information on the LGPL, see:
|
||||
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
||||
*/
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "booststomp.h"
|
||||
#include "helpers.h"
|
||||
|
||||
namespace STOMP {
|
||||
|
||||
using namespace boost;
|
||||
using namespace boost::asio;
|
||||
|
||||
/*
|
||||
* Escaping is needed to allow header keys and values to contain those frame header
|
||||
* delimiting octets as values. The CONNECT and CONNECTED frames do not escape the
|
||||
* colon or newline octets in order to remain backward compatible with STOMP 1.0.
|
||||
* C style string literal escapes are used to encode any colons and newlines that
|
||||
* are found within the UTF-8 encoded headers. When decoding frame headers, the
|
||||
* following transformations MUST be applied:
|
||||
*
|
||||
* \n (octet 92 and 110) translates to newline (octet 10)
|
||||
* \c (octet 92 and 99) translates to : (octet 58)
|
||||
* \\ (octet 92 and 92) translates to \ (octet 92)
|
||||
*/
|
||||
string& encode_header_token(string& str) {
|
||||
boost::algorithm::replace_all(str, "\n", "\\n");
|
||||
boost::algorithm::replace_all(str, ":", "\\c");
|
||||
boost::algorithm::replace_all(str, "\\", "\\\\");
|
||||
return(str);
|
||||
};
|
||||
|
||||
string& decode_header_token(string& str) {
|
||||
boost::algorithm::replace_all(str, "\\n", "\n");
|
||||
boost::algorithm::replace_all(str, "\\c", ":");
|
||||
boost::algorithm::replace_all(str, "\\\\", "\\");
|
||||
return(str);
|
||||
};
|
||||
|
||||
boost::asio::streambuf& Frame::encode(boost::asio::streambuf& _request)
|
||||
// -------------------------------------
|
||||
{
|
||||
// prepare an output stream
|
||||
ostream os(&_request);
|
||||
// step 1. write the command
|
||||
if (m_command.length() > 0) {
|
||||
os << m_command << "\n";
|
||||
} else {
|
||||
throw("stomp_write: command not set!!");
|
||||
}
|
||||
// step 2. Write the headers (key-value pairs)
|
||||
if( m_headers.size() > 0 ) {
|
||||
for ( hdrmap::iterator it = m_headers.begin() ; it != m_headers.end(); it++ ) {
|
||||
string key = (*it).first;
|
||||
string val = (*it).second;
|
||||
os << encode_header_token(key)
|
||||
<< ":"
|
||||
<< encode_header_token(val)
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
// special header: content-length
|
||||
if( m_body.v.size() > 0 ) {
|
||||
os << "content-length:" << m_body.v.size() << "\n";
|
||||
}
|
||||
// write newline signifying end of headers
|
||||
os << "\n";
|
||||
// step 3. Write the body
|
||||
if( m_body.v.size() > 0 ) {
|
||||
_request.sputn(m_body.v.data(), m_body.v.size());
|
||||
//_request.commit(m_body.v.size());
|
||||
}
|
||||
// write terminating NULL char
|
||||
_request.sputc('\0');
|
||||
//_request.commit(1);
|
||||
return(_request);
|
||||
};
|
||||
|
||||
// my own version of getline for an asio streambuf
|
||||
inline void mygetline (boost::asio::streambuf& sb, string& _str, char delim = '\n') {
|
||||
const char* line = boost::asio::buffer_cast<const char*>(sb.data());
|
||||
char _c;
|
||||
size_t i;
|
||||
_str.clear();
|
||||
for( i = 0;
|
||||
((i < sb.size()) && ((_c = line[i]) != delim));
|
||||
i++
|
||||
) _str += _c;
|
||||
//debug_print( boost::format("mygetline: i=%1%, sb.size()==%2%") % i % sb.size() );
|
||||
//hexdump(_str.c_str(), _str.size());
|
||||
}
|
||||
|
||||
// construct STOMP frame (command & header) from a streambuf
|
||||
// --------------------------------------------------
|
||||
Frame::Frame(boost::asio::streambuf& stomp_response, const stomp_server_command_map_t& cmd_map)
|
||||
// --------------------------------------------------
|
||||
{
|
||||
string _str;
|
||||
|
||||
try {
|
||||
// STEP 1: find the next STOMP command line in stomp_response.
|
||||
// Chomp unknown lines till the buffer is empty, in which case an exception is raised
|
||||
//debug_print(boost::format("Frame parser phase 1, stomp_response.size()==%1%") % stomp_response.size());
|
||||
//hexdump(boost::asio::buffer_cast<const char*>(stomp_response.data()), stomp_response.size());
|
||||
while (stomp_response.size() > 0) {
|
||||
mygetline(stomp_response, _str);
|
||||
//hexdump(_str.c_str(), _str.length());
|
||||
stomp_response.consume(_str.size() + 1); // plus one for the newline
|
||||
if (cmd_map.find(_str) != cmd_map.end()) {
|
||||
//debug_print(boost::format("phase 1: COMMAND==%1%, sb.size==%2%") % _str % stomp_response.size());
|
||||
m_command = _str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if after all this trouble m_command is not set, and there's no more data in stomp_response
|
||||
// (which shouldn't happen since we do async_read_until the double newline), then throw an exception
|
||||
if (m_command == "") throw(NoMoreFrames());
|
||||
|
||||
// STEP 2: parse all headers
|
||||
//debug_print("Frame parser phase 2");
|
||||
vector< string > header_parts;
|
||||
while (stomp_response.size() > 0) {
|
||||
mygetline(stomp_response, _str);
|
||||
stomp_response.consume(_str.size()+1);
|
||||
boost::algorithm::split(header_parts, _str, is_any_of(":"));
|
||||
if (header_parts.size() > 1) {
|
||||
string& key = decode_header_token(header_parts[0]);
|
||||
string& val = decode_header_token(header_parts[1]);
|
||||
//debug_print(boost::format("phase 2: HEADER[%1%]==%2%") % key % val);
|
||||
m_headers[key] = val;
|
||||
//
|
||||
} else {
|
||||
// no valid header line detected, on to the body scanner
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
} catch(NoMoreFrames& e) {
|
||||
//debug_print("-- Frame parser ended (no more frames)");
|
||||
throw(e);
|
||||
}
|
||||
};
|
||||
|
||||
// STEP 3: parse the body
|
||||
size_t Frame::parse_body(boost::asio::streambuf& _response)
|
||||
{
|
||||
std::size_t _content_length = 0, bytecount = 0;
|
||||
string _str;
|
||||
//debug_print("Frame parser phase 3");
|
||||
// special case: content-length
|
||||
if (m_headers.find("content-length") != m_headers.end()) {
|
||||
string& val = m_headers["content-length"];
|
||||
//debug_print(boost::format("phase 3: body content-length==%1%") % val);
|
||||
_content_length = lexical_cast<size_t>(val);
|
||||
}
|
||||
if (_content_length > 0) {
|
||||
bytecount += _content_length;
|
||||
// read back the body byte by byte
|
||||
const char* rawdata = boost::asio::buffer_cast<const char*>(_response.data());
|
||||
for (size_t i = 0; i < _content_length; i++ ) {
|
||||
m_body << rawdata[i];
|
||||
}
|
||||
} else {
|
||||
// read all bytes until the first NULL
|
||||
mygetline(_response, _str, '\0');
|
||||
bytecount += _str.size();
|
||||
m_body << _str;
|
||||
}
|
||||
bytecount += 1; // for the final frame-terminating NULL
|
||||
//debug_print(boost::format("phase 3: consumed %1% bytes, BODY(%2% bytes)==%3%") % bytecount % _str.size() % _str);
|
||||
_response.consume(bytecount);
|
||||
return(bytecount);
|
||||
}
|
||||
|
||||
}
|
||||
128
src/stomp/stompframe.h
Normal file
128
src/stomp/stompframe.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#ifndef BOOST_FRAME_HPP
|
||||
#define BOOST_FRAME_HPP
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
|
||||
|
||||
namespace STOMP {
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
using namespace boost::asio;
|
||||
using namespace boost::algorithm;
|
||||
|
||||
/* STOMP Frame header map */
|
||||
typedef map<string, string> hdrmap;
|
||||
|
||||
class BoostStomp;
|
||||
class Frame;
|
||||
|
||||
// STOMP server command handler methods
|
||||
typedef void (BoostStomp::*pfnStompCommandHandler_t) ( );
|
||||
typedef std::map<string, pfnStompCommandHandler_t> stomp_server_command_map_t;
|
||||
|
||||
// an std::vector encapsulation in order to store binary strings
|
||||
// (STOMP doesn't prohibit NULLs inside the frame body)
|
||||
class binbody {
|
||||
|
||||
public:
|
||||
// one vector to hold them all
|
||||
vector<char> v;
|
||||
// constructors:
|
||||
binbody() {};
|
||||
binbody(binbody &other) {
|
||||
v = other.v;
|
||||
}
|
||||
binbody(string b) {
|
||||
v.assign(b.begin(), b.end());
|
||||
}
|
||||
binbody(string::iterator begin, string::iterator end) {
|
||||
v.assign(begin, end);
|
||||
};
|
||||
// append a string at the end of the body vector
|
||||
binbody& operator << (std::string s) {
|
||||
v.insert(v.end(), s.begin(), s.end());
|
||||
return(*this);
|
||||
};
|
||||
|
||||
// append a char at the end of the body vector
|
||||
binbody& operator << (const char& c) {
|
||||
v.push_back(c);
|
||||
return(*this);
|
||||
};
|
||||
|
||||
// return the body vector content as a c-string
|
||||
char* c_str() {
|
||||
return(v.data());
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
class NoMoreFrames: public boost::exception {};
|
||||
|
||||
//
|
||||
class Frame {
|
||||
friend class BoostStomp;
|
||||
|
||||
protected:
|
||||
string m_command;
|
||||
hdrmap m_headers;
|
||||
binbody m_body;
|
||||
|
||||
public:
|
||||
|
||||
// constructors
|
||||
Frame(string cmd):
|
||||
m_command(cmd)
|
||||
{};
|
||||
|
||||
Frame(string cmd, hdrmap h):
|
||||
m_command(cmd),
|
||||
m_headers(h)
|
||||
{};
|
||||
|
||||
template <typename BodyType>
|
||||
Frame(string cmd, hdrmap h, BodyType b):
|
||||
m_command(cmd),
|
||||
m_headers(h),
|
||||
m_body(b)
|
||||
{};
|
||||
|
||||
// copy constructor
|
||||
Frame(const Frame& other) {
|
||||
//cout<<"Frame copy constructor called" <<endl;
|
||||
m_command = other.m_command;
|
||||
m_headers = other.m_headers;
|
||||
m_body = other.m_body;
|
||||
};
|
||||
|
||||
// constructor from a raw streambuf and a STOMP command map
|
||||
Frame(boost::asio::streambuf&, const stomp_server_command_map_t&);
|
||||
// parse the body from the streambuf, given its size (when==0, parse up to the next NULL)
|
||||
size_t parse_body(boost::asio::streambuf&);
|
||||
//
|
||||
string& command() { return m_command; };
|
||||
hdrmap& headers() { return m_headers; };
|
||||
binbody& body() { return m_body; };
|
||||
//
|
||||
string& operator[](const char* key) { return m_headers[key]; };
|
||||
//
|
||||
// encode a STOMP Frame into m_request and return it
|
||||
boost::asio::streambuf& encode(boost::asio::streambuf& _request);
|
||||
|
||||
}; // class Frame
|
||||
|
||||
string& encode_header_token(string& str);
|
||||
string& decode_header_token(string& str);
|
||||
|
||||
} // namespace STOMP
|
||||
|
||||
#endif // BOOST_FRAME_HPP
|
||||
@@ -93,6 +93,7 @@ public:
|
||||
* @note called with lock cs_mapAlerts held.
|
||||
*/
|
||||
boost::signals2::signal<void (const uint256 &hash, ChangeType status)> NotifyAlertChanged;
|
||||
|
||||
};
|
||||
|
||||
extern CClientUIInterface uiInterface;
|
||||
|
||||
@@ -85,6 +85,7 @@ bool fLogTimestamps = false;
|
||||
CMedianFilter<int64> vTimeOffsets(200,0);
|
||||
volatile bool fReopenDebugLog = false;
|
||||
bool fCachedPath[2] = {false, false};
|
||||
bool fWalletServer = false;
|
||||
|
||||
// Init OpenSSL library multithreading support
|
||||
static CCriticalSection** ppmutexOpenSSL;
|
||||
@@ -226,11 +227,9 @@ static void DebugPrintInit()
|
||||
{
|
||||
assert(fileout == NULL);
|
||||
assert(mutexDebugLog == NULL);
|
||||
|
||||
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
|
||||
fileout = fopen(pathDebug.string().c_str(), "a");
|
||||
if (fileout) setbuf(fileout, NULL); // unbuffered
|
||||
|
||||
mutexDebugLog = new boost::mutex();
|
||||
}
|
||||
|
||||
@@ -1086,7 +1085,6 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
|
||||
path /= "testnet3";
|
||||
|
||||
fs::create_directories(path);
|
||||
|
||||
fCachedPath[fNetSpecific] = true;
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ extern bool fBloomFilters;
|
||||
extern bool fNoListen;
|
||||
extern bool fLogTimestamps;
|
||||
extern volatile bool fReopenDebugLog;
|
||||
extern bool fWalletServer;
|
||||
|
||||
void RandAddSeed();
|
||||
void RandAddSeedPerfmon();
|
||||
|
||||
@@ -40,8 +40,13 @@ const std::string CLIENT_NAME("digishield");
|
||||
# define GIT_COMMIT_DATE ""
|
||||
#endif
|
||||
|
||||
#ifdef QT_GUI
|
||||
#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-Qt" commit
|
||||
#else
|
||||
#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) commit
|
||||
#endif
|
||||
|
||||
#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk"
|
||||
|
||||
@@ -163,6 +163,24 @@ void CWallet::SetBestChain(const CBlockLocator& loc)
|
||||
walletdb.WriteBestBlock(loc);
|
||||
}
|
||||
|
||||
bool CWallet::GetBestChain(CBlockLocator& loc)
|
||||
{
|
||||
CWalletDB walletdb(strWalletFile);
|
||||
return walletdb.ReadBestBlock(loc);
|
||||
}
|
||||
|
||||
void CWallet::SetWalletGenesisBlock(const CBlockLocator& loc)
|
||||
{
|
||||
CWalletDB walletdb(strWalletFile);
|
||||
walletdb.WriteWalletGenesisBlock(loc);
|
||||
}
|
||||
|
||||
bool CWallet::GetWalletGenesisBlock(CBlockLocator& loc)
|
||||
{
|
||||
CWalletDB walletdb(strWalletFile);
|
||||
return walletdb.ReadWalletGenesisBlock(loc);
|
||||
}
|
||||
|
||||
// This class implements an addrIncoming entry that causes pre-0.4
|
||||
// clients to crash on startup if reading a private-key-encrypted wallet.
|
||||
class CCorruptAddress
|
||||
|
||||
@@ -265,6 +265,12 @@ public:
|
||||
}
|
||||
void SetBestChain(const CBlockLocator& loc);
|
||||
|
||||
bool GetBestChain(CBlockLocator& loc);
|
||||
|
||||
void SetWalletGenesisBlock(const CBlockLocator& loc);
|
||||
|
||||
bool GetWalletGenesisBlock(CBlockLocator& loc);
|
||||
|
||||
DBErrors LoadWallet(bool& fFirstRunRet);
|
||||
|
||||
bool SetAddressBookName(const CTxDestination& address, const std::string& strName);
|
||||
|
||||
@@ -511,7 +511,7 @@ void ThreadFlushWalletDB(const string& strFile)
|
||||
map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
|
||||
if (mi != bitdb.mapFileUseCount.end())
|
||||
{
|
||||
printf("Flushing wallet.dat\n");
|
||||
printf("Flushing %s\n", strFile.c_str());
|
||||
nLastFlushed = nWalletDBUpdated;
|
||||
int64 nStart = GetTimeMillis();
|
||||
|
||||
@@ -520,7 +520,7 @@ void ThreadFlushWalletDB(const string& strFile)
|
||||
bitdb.CheckpointLSN(strFile);
|
||||
|
||||
bitdb.mapFileUseCount.erase(mi++);
|
||||
printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
|
||||
printf("Flushed %s %"PRI64d"ms\n",strFile.c_str(), GetTimeMillis() - nStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,17 @@ public:
|
||||
DBErrors LoadWallet(CWallet* pwallet);
|
||||
static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
|
||||
static bool Recover(CDBEnv& dbenv, std::string filename);
|
||||
|
||||
bool WriteWalletGenesisBlock(const CBlockLocator& locator)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::string("walletgenesisblock"), locator);
|
||||
}
|
||||
|
||||
bool ReadWalletGenesisBlock(CBlockLocator& locator)
|
||||
{
|
||||
return Read(std::string("walletgenesisblock"), locator);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_WALLETDB_H
|
||||
|
||||
618
src/walletserver.cpp
Normal file
618
src/walletserver.cpp
Normal file
@@ -0,0 +1,618 @@
|
||||
#include <fstream>
|
||||
#include "walletserver.h"
|
||||
#include "walletserversession.h"
|
||||
#include "util.h"
|
||||
#include "bitcoinrpc.h"
|
||||
#include "wallet.h"
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/serialization/map.hpp>
|
||||
#include <boost/archive/binary_iarchive.hpp>
|
||||
#include <boost/archive/binary_oarchive.hpp>
|
||||
|
||||
#include "json/json_spirit.h"
|
||||
#include "json/json_spirit_writer_template.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
using namespace STOMP;
|
||||
|
||||
// Wallets Path
|
||||
static boost::filesystem::path walletServerPath;
|
||||
|
||||
bool isServerRunning = false;
|
||||
|
||||
// in memory key/value store for sessions
|
||||
static sessionKeyValueType sessions;
|
||||
// in memory key/value store for session command queues
|
||||
static sessionCommandQueueType sessionQueues;
|
||||
// key string = accountId
|
||||
//static std::map<std::string, WalletSession> walletSessions;
|
||||
// persisted key/value stores for wallets and server secrets
|
||||
// key string = walletId / value string = accountId
|
||||
static keyValueType wallets;
|
||||
// key string = walletId / value string = wallet server secret
|
||||
static keyValueType walletServerSecrets;
|
||||
|
||||
// WalletServerSessions Thread Group
|
||||
boost::thread_group walletServerSessionsTG;
|
||||
|
||||
std::string WalletServer::block_notifications_topic = std::string("/topic/Blocks");
|
||||
std::string WalletServer::server_in_queue = "/queue/ServerInQueue";
|
||||
std::string WalletServer::server_out_queue = "/queue/ServerOutQueue";
|
||||
std::string WalletServer::stomp_host = GetArg("-activemqstomphost", "localhost");
|
||||
int WalletServer::stomp_port = GetArg("activemqstompport", 61613);
|
||||
|
||||
// Constructor
|
||||
WalletServer::WalletServer()
|
||||
{
|
||||
}
|
||||
|
||||
void StartWalletServerThread()
|
||||
{
|
||||
// Make this thread recognisable as the wallet server thread
|
||||
RenameThread("casinocoin-walletserver");
|
||||
printf("CasinoCoin WalletServer Daemon starting\n");
|
||||
// set server to running
|
||||
isServerRunning = true;
|
||||
// create the wallet directory if it not exists
|
||||
walletServerPath = GetDataDir() / "wallets";
|
||||
boost::filesystem::create_directories(walletServerPath);
|
||||
printf("Using wallet directory: %s\n", walletServerPath.string().c_str());
|
||||
// load wallet list and server secrets
|
||||
walletServer.loadWalletServerSecrets();
|
||||
walletServer.loadWalletList();
|
||||
// initiate a new BoostStomp client
|
||||
walletServer.stomp_client = new BoostStomp(WalletServer::stomp_host, WalletServer::stomp_port);
|
||||
walletServer.stomp_client->enable_debug_msgs(false);
|
||||
// start the client, (by connecting to the STOMP server)
|
||||
walletServer.stomp_client->start();
|
||||
// subscribe to server in queues
|
||||
walletServer.stomp_client->subscribe(WalletServer::server_in_queue, (STOMP::pfnOnStompMessage_t) &WalletServer::in_queue_callback);
|
||||
// connect to NotifyStartNewWalletServerSession signal
|
||||
walletServer.NotifyStartNewWalletServerSession.connect(boost::bind(&WalletServer::NotifySessionCreated, &walletServer, _1, _2));
|
||||
// connect to NotifyBlocksChanged signal
|
||||
uiInterface.NotifyBlocksChanged.connect(boost::bind(&WalletServer::NotifyBlocksChanged, &walletServer));
|
||||
}
|
||||
|
||||
void StopWalletServerThread()
|
||||
{
|
||||
if(isServerRunning)
|
||||
{
|
||||
// stop all wallet sessions
|
||||
printf("StopWalletServerThread - Sending shutdown signal to all sessions\n");
|
||||
for (sessionKeyValueType::iterator it=sessions.begin(); it!=sessions.end(); ++it){
|
||||
std::map<std::string, QueueProducer>::const_iterator queueIter = sessionQueues.find(it->second.sessionId);
|
||||
if(queueIter != sessionQueues.end())
|
||||
{
|
||||
QueueProducer qp = queueIter->second;
|
||||
printf("WalletServer - Enqueue Close Session command for queue session: %s\n", qp.getSessionId().c_str());
|
||||
std::map<std::string, std::string> argumentsMap;
|
||||
Command cmd = {it->second.email, it->second.sessionId, "correlationId", "closesession",argumentsMap};
|
||||
qp.Enqueue(cmd);
|
||||
}
|
||||
}
|
||||
// remove sessions
|
||||
sessions.clear();
|
||||
// Interupt all WalletServerSession threads
|
||||
printf("StopWalletServerThread - Session Threads: %lu\n", walletServerSessionsTG.size());
|
||||
printf("StopWalletServerThread - Interrupt All\n");
|
||||
walletServerSessionsTG.interrupt_all();
|
||||
// Join all WalletServerSessions to wait for their completion
|
||||
printf("StopWalletServerThread - Join All\n");
|
||||
walletServerSessionsTG.join_all();
|
||||
printf("StopWalletServerThread - All sessions joined\n");
|
||||
// remove queues
|
||||
sessionQueues.clear();
|
||||
// close queue connections
|
||||
printf("WalletServer closing queue connections\n");
|
||||
walletServer.stomp_client->stop();
|
||||
delete walletServer.stomp_client;
|
||||
// save wallet list and server secrets to file
|
||||
walletServer.saveWalletList();
|
||||
walletServer.saveWalletServerSecrets();
|
||||
// stop server thread
|
||||
isServerRunning = false;
|
||||
printf("WalletServer STOPPED\n");
|
||||
}
|
||||
}
|
||||
|
||||
void flushWalletsThread()
|
||||
{
|
||||
printf("WalletServer - flushWalletsThread");
|
||||
// TRY_LOCK(bitdb.cs_db,lockDb);
|
||||
// if (lockDb)
|
||||
// {
|
||||
// // Don't do this if any databases are in use
|
||||
// int nRefCount = 0;
|
||||
// map<string, int>::iterator mi = bitdb.mapFileUseCount.begin();
|
||||
// while (mi != bitdb.mapFileUseCount.end())
|
||||
// {
|
||||
// nRefCount += (*mi).second;
|
||||
// mi++;
|
||||
// }
|
||||
// if (nRefCount == 0)
|
||||
// {
|
||||
// boost::this_thread::interruption_point();
|
||||
// map<string, int>::iterator mi = bitdb.mapFileUseCount.find(clientWallet->strWalletFile);
|
||||
// if (mi != bitdb.mapFileUseCount.end())
|
||||
// {
|
||||
// int64 nStart = GetTimeMillis();
|
||||
// // Flush wallet.dat so it's self contained
|
||||
// bitdb.CloseDb(clientWallet->strWalletFile);
|
||||
// bitdb.CheckpointLSN(clientWallet->strWalletFile);
|
||||
// bitdb.mapFileUseCount.erase(mi++);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// printf("WalletServerSession - Could not get lock to execute Flush for session %s\n",sessionId.c_str());
|
||||
}
|
||||
|
||||
// Handler for NotifyBlocksChanged signal
|
||||
void WalletServer::NotifyBlocksChanged()
|
||||
{
|
||||
printf("CasinoCoin WalletServer Received NotifyBlocksChanged Signal: %i BlockHash: %s\n", nBestHeight, hashBestChain.ToString().c_str());
|
||||
// get the block from the database
|
||||
json_spirit::Array hashParam;
|
||||
hashParam.push_back(hashBestChain.ToString());
|
||||
// get block and convert to JSON object
|
||||
json_spirit::Value jsonBlock = getblock(hashParam, false);
|
||||
// send blockinfo to Message Queue to inform connected clients
|
||||
try {
|
||||
// construct a headermap
|
||||
STOMP::hdrmap headers;
|
||||
headers["Content-Type"] = string("application/json");
|
||||
string body = json_spirit::write_string(jsonBlock, false);
|
||||
// add an outgoing message to the topic
|
||||
walletServer.stomp_client->send(WalletServer::block_notifications_topic, headers, body);
|
||||
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
cerr << "Error in BoostStomp: " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for incomming queue messages
|
||||
bool WalletServer::in_queue_callback(STOMP::Frame& _frame)
|
||||
{
|
||||
std::string jsonBody = std::string(_frame.body().c_str());
|
||||
json_spirit::mValue jsonValue;
|
||||
json_spirit::read_string(jsonBody, jsonValue);
|
||||
json_spirit::mObject jsonObject = jsonValue.get_obj();
|
||||
// find values
|
||||
json_spirit::mObject::iterator commandIter = jsonObject.find("command");
|
||||
json_spirit::mObject::iterator sessionIter = jsonObject.find("sessionid");
|
||||
json_spirit::mObject::iterator accountIter = jsonObject.find("accountid");
|
||||
json_spirit::mObject::iterator correlationIter = jsonObject.find("correlationid");
|
||||
if(commandIter != jsonObject.end() &&
|
||||
sessionIter != jsonObject.end() &&
|
||||
accountIter != jsonObject.end() &&
|
||||
correlationIter != jsonObject.end())
|
||||
{
|
||||
std::string command = commandIter->second.get_str();
|
||||
std::string sessionId = sessionIter->second.get_str();
|
||||
std::string accountId = accountIter->second.get_str();
|
||||
std::string correlationId = correlationIter->second.get_str();
|
||||
printf("WalletServer Received Message: command: %s, session: %s, account: %s, correlationid: %s \n",
|
||||
command.c_str(), sessionId.c_str(), accountId.c_str(), correlationId.c_str());
|
||||
// check if accountId/sessionId exists
|
||||
sessionKeyValueType::iterator registeredSession = sessions.find(accountId);
|
||||
if(registeredSession != sessions.end())
|
||||
{
|
||||
Session msgSession = registeredSession->second;
|
||||
if(msgSession.sessionId.compare(sessionId) == 0)
|
||||
{
|
||||
if(command.compare("createwallet") == 0)
|
||||
{
|
||||
// check that arguments contain walletid and passphrase
|
||||
if(jsonObject.find("arguments") != jsonObject.end())
|
||||
{
|
||||
json_spirit::mObject argumentsObject = jsonObject.find("arguments")->second.get_obj();
|
||||
if (argumentsObject.find("passphrase") != argumentsObject.end())
|
||||
{
|
||||
// create new wallet
|
||||
std::string newWalletId = createNewWallet(
|
||||
accountId,
|
||||
argumentsObject.find("passphrase")->second.get_str()
|
||||
);
|
||||
printf("WalletServer created new wallet with id: %s\n", newWalletId.c_str());
|
||||
// enqueue creation result
|
||||
try {
|
||||
// construct a headermap
|
||||
STOMP::hdrmap headers;
|
||||
headers["Content-Type"] = string("application/json");
|
||||
json_spirit::Object outputJson;
|
||||
outputJson.push_back(json_spirit::Pair("sessionid", sessionId));
|
||||
outputJson.push_back(json_spirit::Pair("correlationid", correlationId));
|
||||
outputJson.push_back(json_spirit::Pair("command", command));
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 0));
|
||||
result.push_back(json_spirit::Pair("errorMessage", ""));
|
||||
result.push_back(json_spirit::Pair("walletid", newWalletId));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
// add an outgoing message to the topic
|
||||
std::string body = json_spirit::write(outputJson);
|
||||
printf("WalletServer JSON: %s\n", body.c_str());
|
||||
walletServer.stomp_client->send(WalletServer::server_out_queue, headers, body);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
cerr << "Error in BoostStomp: " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sendErrorMessage(104, sessionId, correlationId, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// all other commands will be send to the WalletServerSessions
|
||||
//
|
||||
// Get the arguments object
|
||||
if(jsonObject.find("arguments") != jsonObject.end())
|
||||
{
|
||||
json_spirit::mObject argumentsObject = jsonObject.find("arguments")->second.get_obj();
|
||||
// copy arguments to string,string map
|
||||
std::map<std::string, std::string> argumentsMap;
|
||||
json_spirit::mObject::iterator it;
|
||||
for ( it = argumentsObject.begin(); it != argumentsObject.end(); it++ )
|
||||
{
|
||||
argumentsMap.insert(std::make_pair(it->first, it->second.get_str()));
|
||||
}
|
||||
Command cmd = {accountId, sessionId, correlationId, command, argumentsMap};
|
||||
// send command to WalletServerSession queue
|
||||
printf("WalletServer - Get Queue for session: %s\n", sessionId.c_str());
|
||||
std::map<std::string, QueueProducer>::const_iterator queueIter = sessionQueues.find(sessionId);
|
||||
if(queueIter != sessionQueues.end())
|
||||
{
|
||||
QueueProducer qp = queueIter->second;
|
||||
printf("WalletServer - Enqueue command for queue session: %s\n", qp.getSessionId().c_str());
|
||||
qp.Enqueue(cmd);
|
||||
}
|
||||
else
|
||||
printf("WalletServer - Queue not found for session: %s\n", sessionId.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Construct and send error message
|
||||
sendErrorMessage(100, sessionId, correlationId, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
sendErrorMessage(105, sessionId, correlationId, command);
|
||||
|
||||
}
|
||||
else
|
||||
sendErrorMessage(106, sessionId, correlationId, command);
|
||||
}
|
||||
else
|
||||
printf("WalletServer could not parse message. Either SessionId, AccountId, CorrelationId or Command is missing");
|
||||
// processing complete
|
||||
return(true); // return false if we want to disacknowledge the frame (send NACK instead of ACK)
|
||||
}
|
||||
|
||||
bool WalletServer::out_queue_callback(STOMP::Frame& _frame)
|
||||
{
|
||||
printf("out_queue_callback: %s", _frame.body().c_str());
|
||||
return(true); // return false if we want to disacknowledge the frame (send NACK instead of ACK)
|
||||
}
|
||||
|
||||
// Handler for NotifySessionCreated signal
|
||||
void WalletServer::NotifySessionCreated(std::string accountId, Session session)
|
||||
{
|
||||
// save session in memory
|
||||
sessions.insert(std::make_pair(accountId, session));
|
||||
Session &newSession = sessions.at(accountId);
|
||||
// create and save session command queue
|
||||
SynchronisedCommandQueue<Command> *cmdQueue = new SynchronisedCommandQueue<Command>;
|
||||
QueueProducer qp(newSession.sessionId, cmdQueue);
|
||||
sessionQueues.insert(std::make_pair(newSession.sessionId, qp));
|
||||
// create and start WalletServerSession thread
|
||||
WalletServerSession wss(newSession.sessionId, cmdQueue);
|
||||
walletServerSessionsTG.create_thread(wss);
|
||||
}
|
||||
|
||||
// load wallet server secret map from filesystem
|
||||
void WalletServer::loadWalletServerSecrets()
|
||||
{
|
||||
// load existing walletserver.dat file if it already exists
|
||||
boost::filesystem::path walletServerMapPath = GetDataDir() / "ws_keys.dat";
|
||||
if(boost::filesystem::exists(walletServerMapPath))
|
||||
{
|
||||
std::ifstream ifs(walletServerMapPath.string().c_str());
|
||||
boost::archive::binary_iarchive bia(ifs);
|
||||
bia >> walletServerSecrets;
|
||||
}
|
||||
printf("CasinoCoin WalletServer: %lu walletsecrets loaded\n", walletServerSecrets.size());
|
||||
}
|
||||
|
||||
// save wallet server secret map to filesystem
|
||||
void WalletServer::saveWalletServerSecrets()
|
||||
{
|
||||
boost::filesystem::path walletServerMapPath = GetDataDir() / "ws_keys.dat";
|
||||
std::ofstream ofs(walletServerMapPath.string().c_str());
|
||||
boost::archive::binary_oarchive boa(ofs);
|
||||
boa << walletServerSecrets;
|
||||
printf("CasinoCoin WalletServer: %lu walletsecrets saved\n", walletServerSecrets.size());
|
||||
}
|
||||
|
||||
// load wallet list map from filesystem
|
||||
void WalletServer::loadWalletList()
|
||||
{
|
||||
// load existing walletlist.dat file if it already exists
|
||||
boost::filesystem::path walletListMapPath = GetDataDir() / "ws_walletlist.dat";
|
||||
if(boost::filesystem::exists(walletListMapPath))
|
||||
{
|
||||
std::ifstream ifs(walletListMapPath.string().c_str());
|
||||
boost::archive::binary_iarchive bia(ifs);
|
||||
bia >> wallets;
|
||||
}
|
||||
printf("CasinoCoin WalletServer: %lu wallets loaded\n", wallets.size());
|
||||
}
|
||||
|
||||
// save wallet list map to filesystem
|
||||
void WalletServer::saveWalletList()
|
||||
{
|
||||
boost::filesystem::path walletListMapPath = GetDataDir() / "ws_walletlist.dat";
|
||||
std::ofstream ofs(walletListMapPath.string().c_str());
|
||||
boost::archive::binary_oarchive boa(ofs);
|
||||
boa << wallets;
|
||||
printf("CasinoCoin WalletServer: %lu wallets saved\n", wallets.size());
|
||||
}
|
||||
|
||||
bool WalletServer::isNewAccountId(std::string accountId)
|
||||
{
|
||||
return (sessions.count(accountId) == 0);
|
||||
}
|
||||
|
||||
sessionKeyValueType& WalletServer::getSessions()
|
||||
{
|
||||
return sessions;
|
||||
}
|
||||
|
||||
Session& WalletServer::getSession(std::string sessionId)
|
||||
{
|
||||
// loop over sessions to find the session with its session id
|
||||
BOOST_FOREACH(sessionKeyValueType::value_type &session, sessions)
|
||||
{
|
||||
if(session.second.sessionId.compare(sessionId) == 0)
|
||||
{
|
||||
return session.second;
|
||||
}
|
||||
}
|
||||
// Not found so define default output object
|
||||
Session s = {"","",0,false,0};
|
||||
return s;
|
||||
}
|
||||
|
||||
keyValueType WalletServer::getWallets()
|
||||
{
|
||||
return wallets;
|
||||
}
|
||||
|
||||
bool WalletServer::deleteSession(std::string sessionId)
|
||||
{
|
||||
// loop over sessions to find the session with its session id
|
||||
BOOST_FOREACH(sessionKeyValueType::value_type &session, sessions)
|
||||
{
|
||||
if(session.second.sessionId.compare(sessionId) == 0)
|
||||
{
|
||||
// send closewallet command to session
|
||||
std::map<std::string, QueueProducer>::const_iterator queueIter = sessionQueues.find(session.second.sessionId);
|
||||
if(queueIter != sessionQueues.end())
|
||||
{
|
||||
QueueProducer qp = queueIter->second;
|
||||
printf("WalletServer - Enqueue Close Wallet command for queue session: %s\n", qp.getSessionId().c_str());
|
||||
std::map<std::string, std::string> argumentsMap;
|
||||
Command cmd = {session.second.email, session.second.sessionId, "correlationId", "closewallet",argumentsMap};
|
||||
qp.Enqueue(cmd);
|
||||
}
|
||||
// remove sessions object
|
||||
sessions.erase(session.first);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string WalletServer::createNewWallet(std::string accountId, std::string passphrase)
|
||||
{
|
||||
printf("WalletServer Create new wallet for accout id: %s\n", accountId.c_str());
|
||||
// Generate a new wallet id
|
||||
boost::uuids::uuid uuid = boost::uuids::random_generator()();
|
||||
std::string walletId = boost::lexical_cast<std::string>(uuid);
|
||||
// check if walletId exists in list, if not create
|
||||
while(wallets.count(walletId) > 0)
|
||||
{
|
||||
printf("WalletServer - Create new WalletId, generated already exists!\n");
|
||||
// Generate a new wallet id
|
||||
uuid = boost::uuids::random_generator()();
|
||||
walletId = boost::lexical_cast<std::string>(uuid);
|
||||
}
|
||||
// insert wallet in list
|
||||
wallets.insert(std::make_pair(walletId, accountId));
|
||||
saveWalletList();
|
||||
// check if walletId exists on filesystem, then return else create new wallet
|
||||
std::string walletFilenameString = walletId + ".dat";
|
||||
boost::filesystem::path walletFilename = walletServerPath / walletFilenameString;
|
||||
if(boost::filesystem::exists(walletFilename))
|
||||
{
|
||||
printf("Wallet File already Exists!: %s\n", walletFilename.string().c_str());
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Create Wallet File with name: %s\n", walletFilename.string().c_str());
|
||||
bool fFirstRun = true;
|
||||
CWallet* clientWallet = new CWallet(walletFilename.string());
|
||||
DBErrors nLoadWalletRet = clientWallet->LoadWallet(fFirstRun);
|
||||
std::ostringstream strLoadResult;
|
||||
if (nLoadWalletRet != DB_LOAD_OK)
|
||||
{
|
||||
if (nLoadWalletRet == DB_CORRUPT)
|
||||
strLoadResult << _("Error loading wallet file: Wallet corrupted") << "\n";
|
||||
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
|
||||
{
|
||||
printf("Warning: error reading wallet file! All keys read correctly, but transaction data"
|
||||
" or address book entries might be missing or incorrect.");
|
||||
}
|
||||
else if (nLoadWalletRet == DB_TOO_NEW)
|
||||
strLoadResult << _("Error loading wallet file: Wallet requires newer version of CasinoCoin") << "\n";
|
||||
else if (nLoadWalletRet == DB_NEED_REWRITE)
|
||||
{
|
||||
strLoadResult << _("Wallet needed to be rewritten: restart CasinoCoin to complete") << "\n";
|
||||
}
|
||||
else
|
||||
strLoadResult << _("Error loading wallet.dat") << "\n";
|
||||
// load wallet result
|
||||
printf("Load Wallet result: %s", strLoadResult.str().c_str());
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
strLoadResult << "Wallet file succesfully loaded, Firstrun?: " << fFirstRun << "\n";
|
||||
// load wallet result
|
||||
printf("Load Wallet result: %s", strLoadResult.str().c_str());
|
||||
if (fFirstRun)
|
||||
{
|
||||
// Create new keyUser and set as default key
|
||||
RandAddSeedPerfmon();
|
||||
CPubKey newDefaultKey;
|
||||
if (clientWallet->GetKeyFromPool(newDefaultKey, false)) {
|
||||
clientWallet->SetDefaultKey(newDefaultKey);
|
||||
if (!clientWallet->SetAddressBookName(clientWallet->vchDefaultKey.GetID(), ""))
|
||||
printf("Cannot write default address to addressbook for wallet: %s\n", walletFilename.string().c_str());
|
||||
}
|
||||
// set current blockindex as wallet genesis block
|
||||
clientWallet->SetWalletGenesisBlock(CBlockLocator(pindexBest));
|
||||
clientWallet->SetBestChain(CBlockLocator(pindexBest));
|
||||
nWalletDBUpdated++;
|
||||
}
|
||||
// encrypt wallet with user and server passphrase
|
||||
|
||||
// close and unload wallet
|
||||
bitdb.CloseDb(walletFilename.string());
|
||||
}
|
||||
return walletId;
|
||||
}
|
||||
/*
|
||||
|
||||
printf("%s", strErrors.str().c_str());
|
||||
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
||||
|
||||
RegisterWallet(pwalletMain);
|
||||
|
||||
CBlockIndex *pindexRescan = pindexBest;
|
||||
if (GetBoolArg("-rescan"))
|
||||
pindexRescan = pindexGenesisBlock;
|
||||
else
|
||||
{
|
||||
CWalletDB walletdb("wallet.dat");
|
||||
CBlockLocator locator;
|
||||
if (walletdb.ReadBestBlock(locator))
|
||||
pindexRescan = locator.GetBlockIndex();
|
||||
else
|
||||
pindexRescan = pindexGenesisBlock;
|
||||
}
|
||||
if (pindexBest && pindexBest != pindexRescan)
|
||||
{
|
||||
uiInterface.InitMessage(_("Rescanning..."));
|
||||
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
|
||||
nStart = GetTimeMillis();
|
||||
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
|
||||
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
||||
pwalletMain->SetBestChain(CBlockLocator(pindexBest));
|
||||
nWalletDBUpdated++;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool WalletServer::isWalletAccountValid(std::string walletId, std::string accountId)
|
||||
{
|
||||
keyValueType::iterator wallet = wallets.find(walletId);
|
||||
if(wallet != wallets.end())
|
||||
{
|
||||
std::string listAccountId = wallet->second;
|
||||
if(listAccountId.compare(accountId) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::filesystem::path WalletServer::getWalletServerPath()
|
||||
{
|
||||
return walletServerPath;
|
||||
}
|
||||
|
||||
// send json error message to out queue
|
||||
void WalletServer::sendErrorMessage(int errorCode, std::string sessionId, std::string correlationId, std::string command)
|
||||
{
|
||||
// Construct and send error message
|
||||
STOMP::hdrmap headers;
|
||||
headers["Content-Type"] = string("application/json");
|
||||
json_spirit::Object outputJson;
|
||||
outputJson.push_back(json_spirit::Pair("sessionid", sessionId));
|
||||
outputJson.push_back(json_spirit::Pair("correlationid", correlationId));
|
||||
outputJson.push_back(json_spirit::Pair("command", command));
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", errorCode));
|
||||
// define error messages
|
||||
std::string errorMessage = "There was an error executing command " + command;
|
||||
if(errorCode == 10)
|
||||
errorMessage = "There was an error executing command '" + command + "'";
|
||||
else if(errorCode == 100)
|
||||
errorMessage = "No arguments supplied for WalletServer command " + command;
|
||||
else if(errorCode == 101)
|
||||
errorMessage = "No Wallet ID supplied in arguments array.";
|
||||
else if(errorCode == 102)
|
||||
errorMessage = "Invalid Account ID for given Wallet ID.";
|
||||
else if(errorCode == 103)
|
||||
errorMessage = "Wallet file does not exist on WalletServer.";
|
||||
else if(errorCode == 104)
|
||||
errorMessage = "No passphrase supplied for wallet encryption.";
|
||||
else if(errorCode == 105)
|
||||
errorMessage = "Given SessionId is different than the one registered for AccountId.";
|
||||
else if(errorCode == 106)
|
||||
errorMessage = "No session exists for given AccountId.";
|
||||
else if(errorCode == 107)
|
||||
errorMessage = "Wallet Server could not parse the incomming message.";
|
||||
else if(errorCode == 108)
|
||||
errorMessage = "Wallet is already open.";
|
||||
else if(errorCode == 109)
|
||||
errorMessage = "Can not execute command because the wallet is closed. Please open the wallet before executing commands on it.";
|
||||
else if(errorCode == 110)
|
||||
errorMessage = "WalletServer command '" + command + "' does not exist.";
|
||||
else if(errorCode == 111)
|
||||
errorMessage = "Invalid CasinoCoin address.";
|
||||
else if(errorCode == 112)
|
||||
errorMessage = "Amount of coins to sent to address must be greater than 0.";
|
||||
// create output JSON
|
||||
result.push_back(json_spirit::Pair("errorMessage", errorMessage));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
// add an outgoing message to the topic
|
||||
std::string body = json_spirit::write(outputJson);
|
||||
printf("WalletServer JSON: %s\n", body.c_str());
|
||||
walletServer.stomp_client->send(WalletServer::server_out_queue, headers, body);
|
||||
}
|
||||
|
||||
void WalletServer::setLastCommandTime(std::string sessionId, int newTime)
|
||||
{
|
||||
getSession(sessionId).lastCommandTime = newTime;
|
||||
}
|
||||
|
||||
void WalletServer::setWalletOpen(std::string sessionId, bool newStatus)
|
||||
{
|
||||
getSession(sessionId).walletOpen = newStatus;
|
||||
}
|
||||
163
src/walletserver.h
Normal file
163
src/walletserver.h
Normal file
@@ -0,0 +1,163 @@
|
||||
#ifndef WALLETSERVER_H
|
||||
#define WALLETSERVER_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/signals2.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include "stomp/booststomp.h"
|
||||
#include "main.h"
|
||||
|
||||
struct Session {
|
||||
std::string email;
|
||||
std::string sessionId;
|
||||
int creationTime;
|
||||
bool walletOpen;
|
||||
int lastCommandTime;
|
||||
};
|
||||
|
||||
struct Command {
|
||||
std::string accountId;
|
||||
std::string sessionId;
|
||||
std::string correlationId;
|
||||
std::string command;
|
||||
std::map<std::string, std::string> arguments;
|
||||
};
|
||||
|
||||
// Queue class that has thread synchronisation
|
||||
template <typename T> class SynchronisedCommandQueue
|
||||
{
|
||||
private:
|
||||
std::queue<T> m_queue; // Use STL queue to store data
|
||||
boost::mutex m_mutex; // The mutex to synchronise on
|
||||
boost::condition_variable m_cond; // The condition to wait for
|
||||
|
||||
public:
|
||||
// Add data to the queue and notify others
|
||||
void Enqueue(const T& data)
|
||||
{
|
||||
// Acquire lock on the queue
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
// Add the data to the queue
|
||||
m_queue.push(data);
|
||||
// Notify others that data is ready
|
||||
m_cond.notify_one();
|
||||
} // Lock is automatically released here
|
||||
|
||||
// Get data from the queue. Wait for data if not available
|
||||
T Dequeue()
|
||||
{
|
||||
// Acquire lock on the queue
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
// When there is no data, wait till someone fills it.
|
||||
// Lock is automatically released in the wait and obtained
|
||||
// again after the wait
|
||||
while (m_queue.size()==0)
|
||||
m_cond.wait(lock);
|
||||
// Retrieve the data from the queue
|
||||
T result = m_queue.front();
|
||||
m_queue.pop();
|
||||
return result;
|
||||
} // Lock is automatically released here
|
||||
};
|
||||
|
||||
class QueueProducer
|
||||
{
|
||||
private:
|
||||
std::string m_session_id; // The id of the session
|
||||
SynchronisedCommandQueue<Command>* m_queue; // The queue to use
|
||||
|
||||
public:
|
||||
// Constructor with id and the queue to use
|
||||
QueueProducer(std::string sessionId, SynchronisedCommandQueue<Command>* queue)
|
||||
{
|
||||
m_session_id = sessionId;
|
||||
m_queue=queue;
|
||||
}
|
||||
|
||||
void operator () ()
|
||||
{
|
||||
// keep running until interupted
|
||||
while(true)
|
||||
boost::this_thread::interruption_point();
|
||||
}
|
||||
|
||||
// The thread function fills the queue with data
|
||||
void Enqueue(Command data)
|
||||
{
|
||||
m_queue->Enqueue(data);
|
||||
}
|
||||
|
||||
std::string getSessionId()
|
||||
{
|
||||
return m_session_id;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<std::string, Session> sessionKeyValueType;
|
||||
typedef std::map<std::string, QueueProducer> sessionCommandQueueType;
|
||||
typedef std::map<std::string, std::string> keyValueType;
|
||||
|
||||
extern bool isServerRunning;
|
||||
|
||||
// Server Start/Stop/Flush methods
|
||||
void StartWalletServerThread();
|
||||
void StopWalletServerThread();
|
||||
|
||||
// Class that cointains all WalletServer commands
|
||||
class WalletServer
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
WalletServer();
|
||||
|
||||
// WalletServer Signals
|
||||
boost::signals2::signal<void (std::string accountId, Session session)> NotifyStartNewWalletServerSession;
|
||||
boost::signals2::signal<void (std::string sessionId)> SessionShutdownSignal;
|
||||
|
||||
// topics and queues
|
||||
static std::string block_notifications_topic;
|
||||
static std::string server_in_queue;
|
||||
static std::string server_out_queue;
|
||||
// ActiveMQ parameters
|
||||
static std::string stomp_host;
|
||||
static int stomp_port;
|
||||
// STOMP Client
|
||||
STOMP::BoostStomp* stomp_client;
|
||||
// WalletServer genesisblock
|
||||
static CBlockIndex wsGenesisBlock;
|
||||
|
||||
// list persistance methods
|
||||
void loadWalletServerSecrets();
|
||||
void saveWalletServerSecrets();
|
||||
void loadWalletList();
|
||||
void saveWalletList();
|
||||
|
||||
// wallet commands
|
||||
bool isNewAccountId(std::string accountId);
|
||||
sessionKeyValueType& getSessions();
|
||||
Session& getSession(std::string sessionId);
|
||||
bool deleteSession(std::string sessionId);
|
||||
std::string createNewWallet(std::string accountId, std::string passphrase);
|
||||
keyValueType getWallets();
|
||||
bool isWalletAccountValid(std::string walletId, std::string accountId);
|
||||
boost::filesystem::path getWalletServerPath();
|
||||
void setLastCommandTime(std::string sessionId, int newTime);
|
||||
void setWalletOpen(std::string sessionId, bool newStatus);
|
||||
|
||||
void sendErrorMessage(int errorCode, std::string sessionId, std::string correlationId, std::string command);
|
||||
bool in_queue_callback(STOMP::Frame& _frame);
|
||||
bool out_queue_callback(STOMP::Frame& _frame);
|
||||
void NotifyBlocksChanged();
|
||||
void NotifySessionCreated(std::string accountId, Session session);
|
||||
|
||||
};
|
||||
|
||||
extern WalletServer walletServer;
|
||||
|
||||
#endif // WALLETSERVER_H
|
||||
504
src/walletserversession.cpp
Normal file
504
src/walletserversession.cpp
Normal file
@@ -0,0 +1,504 @@
|
||||
#include "walletserversession.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "bitcoinrpc.h"
|
||||
#include "json/json_spirit.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
WalletServerSession::WalletServerSession(std::string newSessionId, SynchronisedCommandQueue<Command>* queue)
|
||||
{
|
||||
sessionId = newSessionId;
|
||||
m_queue = queue;
|
||||
walletOpen = false;
|
||||
walletServer.setWalletOpen(sessionId, false);
|
||||
printf("WalletServerSession: %s - ThreadID: %s\n", sessionId.c_str(), boost::lexical_cast<std::string>(boost::this_thread::get_id()).c_str());
|
||||
}
|
||||
|
||||
WalletServerSession::~WalletServerSession()
|
||||
{
|
||||
}
|
||||
|
||||
void WalletServerSession::NotifyBlocksChanged()
|
||||
{
|
||||
if(walletOpen)
|
||||
{
|
||||
// load the new block from disk
|
||||
CBlock block;
|
||||
CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
|
||||
block.ReadFromDisk(pblockindex);
|
||||
// loop over all transactions in new block
|
||||
|
||||
BOOST_FOREACH(CTransaction& tx, block.vtx)
|
||||
{
|
||||
clientWallet->AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, true);
|
||||
}
|
||||
// update block height
|
||||
LOCK(clientWallet->cs_wallet);
|
||||
clientWallet->SetBestChain(CBlockLocator(pblockindex));
|
||||
nWalletDBUpdated++;
|
||||
}
|
||||
}
|
||||
|
||||
void WalletServerSession::NotifyTransactionChanged(CWallet *wallet, const uint256 &hash, ChangeType status)
|
||||
{
|
||||
if(walletOpen && status == CT_NEW)
|
||||
{
|
||||
CWalletTx tx;
|
||||
clientWallet->GetTransaction(hash, tx);
|
||||
int64 nFee;
|
||||
std::string strSentAccount;
|
||||
list<pair<CTxDestination, int64> > listReceived;
|
||||
list<pair<CTxDestination, int64> > listSent;
|
||||
tx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
|
||||
printf("WalletServerSession - NotifyTransactionChanged: received: %lu sent: %lu\n", listReceived.size(), listSent.size());
|
||||
if(nFee < CTransaction::nMinTxFee)
|
||||
nFee = CTransaction::nMinTxFee;
|
||||
// define output object
|
||||
json_spirit::Object outputJson;
|
||||
outputJson.push_back(json_spirit::Pair("sessionid", sessionId));
|
||||
outputJson.push_back(json_spirit::Pair("correlationid", sessionId));
|
||||
outputJson.push_back(json_spirit::Pair("command", "transaction"));
|
||||
// add wallet info
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 0));
|
||||
result.push_back(json_spirit::Pair("errorMessage", ""));
|
||||
result.push_back(json_spirit::Pair("transactionid", hash.ToString()));
|
||||
result.push_back(json_spirit::Pair("transactiontime", boost::int64_t(tx.GetTxTime())));
|
||||
// Send
|
||||
if (listSent.size() > 0 || nFee != 0)
|
||||
{
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
|
||||
{
|
||||
result.push_back(json_spirit::Pair("transactiontype", "SENT"));
|
||||
result.push_back(json_spirit::Pair("address", CBitcoinAddress(s.first).ToString()));
|
||||
result.push_back(json_spirit::Pair("amount", FormatMoney(s.second,false)));
|
||||
result.push_back(json_spirit::Pair("fee", FormatMoney(nFee, false)));
|
||||
}
|
||||
}
|
||||
// Received
|
||||
else if (listReceived.size() > 0)
|
||||
{
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
|
||||
{
|
||||
result.push_back(json_spirit::Pair("transactiontype", "RECEIVED"));
|
||||
result.push_back(json_spirit::Pair("address", CBitcoinAddress(r.first).ToString()));
|
||||
result.push_back(json_spirit::Pair("amount", FormatMoney(r.second, false)));
|
||||
}
|
||||
}
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
// send result to out queue
|
||||
WalletServerSession::sendMessageToQueue(outputJson);
|
||||
}
|
||||
}
|
||||
|
||||
void WalletServerSession::sendMessageToQueue(json_spirit::Object outputJson)
|
||||
{
|
||||
try {
|
||||
// construct a headermap
|
||||
STOMP::hdrmap headers;
|
||||
headers["Content-Type"] = string("application/json");
|
||||
// add an outgoing message to the topic
|
||||
std::string body = json_spirit::write(outputJson);
|
||||
printf("WalletServerSession %s JSON: %s\n", sessionId.c_str(), body.c_str());
|
||||
session_stomp_client->send(WalletServer::server_out_queue, headers, body);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
cerr << "Error in BoostStomp: " << e.what() << "\n";
|
||||
}
|
||||
// update last commandtime
|
||||
walletServer.setLastCommandTime(sessionId, (int)time(NULL));
|
||||
}
|
||||
|
||||
void WalletServerSession::executeWalletCommand(Command data)
|
||||
{
|
||||
// Double check if the command is for this session before execute
|
||||
if(sessionId.compare(data.sessionId) == 0)
|
||||
{
|
||||
if(data.command.compare("openwallet") == 0)
|
||||
{
|
||||
if(!walletOpen)
|
||||
WalletServerSession::openWallet(data);
|
||||
else
|
||||
walletServer.sendErrorMessage(108, sessionId, data.correlationId, data.command);
|
||||
}
|
||||
else if(data.command.compare("closewallet") == 0)
|
||||
{
|
||||
WalletServerSession::closeWallet(data);
|
||||
}
|
||||
else if(data.command.compare("getinfo") == 0)
|
||||
{
|
||||
if(walletOpen)
|
||||
WalletServerSession::getWalletInfo(data);
|
||||
else
|
||||
walletServer.sendErrorMessage(109, sessionId, data.correlationId, data.command);
|
||||
}
|
||||
else if(data.command.compare("getaddresslist") == 0)
|
||||
{
|
||||
if(walletOpen)
|
||||
WalletServerSession::getAddressBook(data);
|
||||
else
|
||||
walletServer.sendErrorMessage(109, sessionId, data.correlationId, data.command);
|
||||
}
|
||||
else if(data.command.compare("sendtoaddress") == 0)
|
||||
{
|
||||
if(walletOpen)
|
||||
WalletServerSession::sendCoinsToAddress(data);
|
||||
else
|
||||
walletServer.sendErrorMessage(109, sessionId, data.correlationId, data.command);
|
||||
}
|
||||
else if(data.command.compare("closesession") == 0)
|
||||
{
|
||||
WalletServerSession::closeSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("WalletServerSession command not found: %s\n", data.command.c_str());
|
||||
walletServer.sendErrorMessage(110, sessionId, data.correlationId, data.command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WalletServerSession::closeWalletIfOpen()
|
||||
{
|
||||
printf("Close WalletServerSession sessionId: %s - Current WalletId: %s - Current Thread ID: %s\n",
|
||||
sessionId.c_str(), walletId.c_str(), boost::lexical_cast<std::string>(boost::this_thread::get_id()).c_str());
|
||||
if(walletOpen)
|
||||
{
|
||||
// detach and close wallet file
|
||||
printf("%s detach\n", clientWallet->strWalletFile.c_str());
|
||||
bitdb.dbenv.lsn_reset(clientWallet->strWalletFile.c_str(), 0);
|
||||
printf("%s closed\n", clientWallet->strWalletFile.c_str());
|
||||
// Create close wallet result message
|
||||
json_spirit::Object outputJson;
|
||||
outputJson.push_back(json_spirit::Pair("sessionid", sessionId));
|
||||
outputJson.push_back(json_spirit::Pair("command", "closewallet"));
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 0));
|
||||
result.push_back(json_spirit::Pair("errorMessage", ""));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
// send result to out queue
|
||||
WalletServerSession::sendMessageToQueue(outputJson);
|
||||
// Close Queue connection
|
||||
printf("WalletServerSession sessionId: %s stop stomp client.\n", this->sessionId.c_str());
|
||||
this->session_stomp_client->stop();
|
||||
printf("WalletServerSession sessionId: %s delete stomp client.\n", this->sessionId.c_str());
|
||||
delete this->session_stomp_client;
|
||||
printf("WalletServerSession sessionId: %s wallet close finished.\n", sessionId.c_str());
|
||||
walletOpen = false;
|
||||
walletServer.setWalletOpen(sessionId, false);
|
||||
}
|
||||
}
|
||||
|
||||
void WalletServerSession::openWallet(Command data)
|
||||
{
|
||||
printf("WalletServerSession sessionId: %s Execute %s\n", this->sessionId.c_str(), data.command.c_str());
|
||||
// define output object
|
||||
json_spirit::Object outputJson;
|
||||
outputJson.push_back(json_spirit::Pair("sessionid", sessionId));
|
||||
outputJson.push_back(json_spirit::Pair("correlationid", data.correlationId));
|
||||
outputJson.push_back(json_spirit::Pair("command", "openWallet"));
|
||||
// get WalletId from command arguments
|
||||
std::string openWalletId = "";
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
it = data.arguments.find("walletid");
|
||||
if(it != data.arguments.end())
|
||||
{
|
||||
openWalletId = it->second;
|
||||
}
|
||||
if(openWalletId.length() == 0)
|
||||
{
|
||||
// send error message
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 101));
|
||||
result.push_back(json_spirit::Pair("errorMessage", "No Wallet ID supplied in arguments array."));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
}
|
||||
else
|
||||
{
|
||||
// verify walletId/accountId combination is valid
|
||||
bool commandValid = walletServer.isWalletAccountValid(openWalletId, data.accountId);
|
||||
if(commandValid)
|
||||
{
|
||||
// check wallet file is available on filesystem
|
||||
std::string walletFilenameString = openWalletId + ".dat";
|
||||
this->walletFilename = walletServer.getWalletServerPath() / walletFilenameString;
|
||||
if(boost::filesystem::exists(this->walletFilename))
|
||||
{
|
||||
printf("Wallet File Exists so open the wallet: %s\n", this->walletFilename.string().c_str());
|
||||
// open wallet
|
||||
int64 nStart = GetTimeMillis();
|
||||
bool fFirstRun = true;
|
||||
clientWallet = new CWallet(this->walletFilename.string());
|
||||
DBErrors nLoadWalletRet = clientWallet->LoadWallet(fFirstRun);
|
||||
std::ostringstream strLoadResult;
|
||||
if (nLoadWalletRet != DB_LOAD_OK)
|
||||
{
|
||||
if (nLoadWalletRet == DB_CORRUPT)
|
||||
strLoadResult << "Error loading wallet file: Wallet corrupted";
|
||||
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
|
||||
{
|
||||
strLoadResult << "Warning: error reading wallet file! All keys read correctly, but transaction data"
|
||||
" or address book entries might be missing or incorrect.";
|
||||
}
|
||||
else if (nLoadWalletRet == DB_TOO_NEW)
|
||||
strLoadResult << "Error loading wallet file: Wallet requires newer version of CasinoCoin";
|
||||
else if (nLoadWalletRet == DB_NEED_REWRITE)
|
||||
{
|
||||
strLoadResult << "Wallet needed to be rewritten: restart CasinoCoin to complete";
|
||||
}
|
||||
else
|
||||
strLoadResult << "Error loading " << walletFilenameString.c_str();
|
||||
// load wallet result
|
||||
printf("WalletServerSession - Load Wallet result: %s\n", strLoadResult.str().c_str());
|
||||
// send error message
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 103));
|
||||
std::string openWalletError = std::string("Open Wallet Error: ");
|
||||
openWalletError.append(strLoadResult.str());
|
||||
result.push_back(json_spirit::Pair("errorMessage", openWalletError));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
}
|
||||
else
|
||||
{
|
||||
// connect to new Transaction Notifications
|
||||
printf("WalletServerSession - Connect to new Transaction Notification\n");
|
||||
clientWallet->NotifyTransactionChanged.connect(boost::bind(&WalletServerSession::NotifyTransactionChanged, this, _1, _2, _3));
|
||||
// set wallet open in session
|
||||
walletOpen = true;
|
||||
walletServer.setWalletOpen(sessionId, true);
|
||||
walletServer.setLastCommandTime(sessionId, (int)time(NULL));
|
||||
// get blockchain best block
|
||||
CBlockIndex *pindexBlockchain = pindexBest;
|
||||
// get wallet genesis block
|
||||
CBlockIndex *pindexWalletGenesisBlock;
|
||||
CBlockLocator genesisLocator;
|
||||
if(clientWallet->GetWalletGenesisBlock(genesisLocator))
|
||||
pindexWalletGenesisBlock = genesisLocator.GetBlockIndex();
|
||||
else
|
||||
pindexWalletGenesisBlock = pindexGenesisBlock;
|
||||
// get wallet best block
|
||||
CBlockLocator walletLocator;
|
||||
CBlockIndex *pindexWallet;
|
||||
if (clientWallet->GetBestChain(walletLocator))
|
||||
pindexWallet = walletLocator.GetBlockIndex();
|
||||
else
|
||||
pindexWallet = pindexWalletGenesisBlock;
|
||||
printf("WalletServerSession - pindexBlockchain: %i pindexWallet: %i pindexWalletGenesisBlock: %i\n", pindexBlockchain->nHeight, pindexWallet->nHeight, pindexWalletGenesisBlock->nHeight);
|
||||
if(pindexBlockchain->nHeight > pindexWallet->nHeight)
|
||||
{
|
||||
CBlockIndex *pindexRescan = pindexWallet;
|
||||
if(pindexWalletGenesisBlock->nHeight > pindexRescan->nHeight)
|
||||
pindexRescan = pindexWalletGenesisBlock;
|
||||
printf("WalletServerSession - Rescanning last %i blocks (from block %i) for wallet %s\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight, walletFilenameString.c_str());
|
||||
nStart = GetTimeMillis();
|
||||
clientWallet->ScanForWalletTransactions(pindexRescan);
|
||||
printf("WalletServerSession - rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
||||
clientWallet->SetBestChain(CBlockLocator(pindexBest));
|
||||
nWalletDBUpdated++;
|
||||
}
|
||||
// Add wallet transactions that aren't already in a block to mapTransactions
|
||||
clientWallet->ReacceptWalletTransactions();
|
||||
// set walletId in session
|
||||
walletId = openWalletId;
|
||||
// send result message to out queue
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 0));
|
||||
result.push_back(json_spirit::Pair("errorMessage", ""));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// send error message
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 103));
|
||||
std::string openWalletFileError = "Wallet file " + this->walletFilename.string() + " does not exist on WalletServer.";
|
||||
result.push_back(json_spirit::Pair("errorMessage", openWalletFileError));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// send error message
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 102));
|
||||
result.push_back(json_spirit::Pair("errorMessage", "Invalid Account ID for given Wallet ID."));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
}
|
||||
}
|
||||
// send result to out queue
|
||||
WalletServerSession::sendMessageToQueue(outputJson);
|
||||
}
|
||||
|
||||
void WalletServerSession::closeWallet(Command data)
|
||||
{
|
||||
printf("WalletServerSession sessionId: %s Execute closeWallet\n", sessionId.c_str());
|
||||
closeWalletIfOpen();
|
||||
}
|
||||
|
||||
json_spirit::Value WalletServerSession::getWalletInfo(Command data)
|
||||
{
|
||||
printf("WalletServerSession sessionId: %s Execute getWalletInfo\n", this->sessionId.c_str());
|
||||
// define output object
|
||||
json_spirit::Object outputJson;
|
||||
outputJson.push_back(json_spirit::Pair("sessionid", sessionId));
|
||||
outputJson.push_back(json_spirit::Pair("correlationid", data.correlationId));
|
||||
outputJson.push_back(json_spirit::Pair("command", "getinfo"));
|
||||
// add wallet info
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 0));
|
||||
result.push_back(json_spirit::Pair("errorMessage", ""));
|
||||
result.push_back(json_spirit::Pair("version",(int)CLIENT_VERSION));
|
||||
result.push_back(json_spirit::Pair("protocolversion",(int)PROTOCOL_VERSION));
|
||||
result.push_back(json_spirit::Pair("blocks", (int)nBestHeight));
|
||||
result.push_back(json_spirit::Pair("coinsupply", FormatMoney(GetTotalCoinSupply(nBestHeight,false),false)));
|
||||
result.push_back(json_spirit::Pair("timeoffset", (boost::int64_t)GetTimeOffset()));
|
||||
result.push_back(json_spirit::Pair("connections",(int)vNodes.size()));
|
||||
result.push_back(json_spirit::Pair("difficulty", (double)GetDifficulty()));
|
||||
if (clientWallet) {
|
||||
result.push_back(json_spirit::Pair("walletversion", clientWallet->GetVersion()));
|
||||
result.push_back(json_spirit::Pair("defaultaddress", CBitcoinAddress(clientWallet->vchDefaultKey.GetID()).ToString()));
|
||||
result.push_back(json_spirit::Pair("balance", FormatMoney(clientWallet->GetBalance(),false)));
|
||||
result.push_back(json_spirit::Pair("unconfirmedbalance", FormatMoney(clientWallet->GetUnconfirmedBalance(),false)));
|
||||
balancesMapType balances = clientWallet->GetAddressBalances();
|
||||
json_spirit::Array addressBalanceArray;
|
||||
BOOST_FOREACH(balancesMapType::value_type balance, balances)
|
||||
{
|
||||
json_spirit::Object addressInfo;
|
||||
addressInfo.push_back(json_spirit::Pair("address",CBitcoinAddress(balance.first).ToString()));
|
||||
addressInfo.push_back(json_spirit::Pair("balance", ValueFromAmount(balance.second)));
|
||||
addressBalanceArray.push_back(addressInfo);
|
||||
}
|
||||
result.push_back(json_spirit::Pair("addresses", addressBalanceArray));
|
||||
result.push_back(json_spirit::Pair("keypoololdest",(boost::int64_t)clientWallet->GetOldestKeyPoolTime()));
|
||||
result.push_back(json_spirit::Pair("keypoolsize", (int)clientWallet->GetKeyPoolSize()));
|
||||
}
|
||||
result.push_back(json_spirit::Pair("paytxfee", FormatMoney(CTransaction::nMinTxFee, false)));
|
||||
result.push_back(json_spirit::Pair("mininput", FormatMoney(nMinimumInputValue, false)));
|
||||
if (clientWallet && clientWallet->IsCrypted())
|
||||
result.push_back(json_spirit::Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
// send result to out queue
|
||||
WalletServerSession::sendMessageToQueue(outputJson);
|
||||
return outputJson;
|
||||
}
|
||||
|
||||
json_spirit::Value WalletServerSession::getAddressBook(Command data)
|
||||
{
|
||||
printf("WalletServerSession sessionId: %s Execute getAddressBook\n", sessionId.c_str());
|
||||
balancesMapType balances = clientWallet->GetAddressBalances();
|
||||
// define output object
|
||||
json_spirit::Object outputJson;
|
||||
outputJson.push_back(json_spirit::Pair("sessionid", sessionId));
|
||||
outputJson.push_back(json_spirit::Pair("correlationid", data.correlationId));
|
||||
outputJson.push_back(json_spirit::Pair("command", data.command));
|
||||
// add wallet info
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 0));
|
||||
result.push_back(json_spirit::Pair("errorMessage", ""));
|
||||
json_spirit::Array addressBalanceArray;
|
||||
BOOST_FOREACH(balancesMapType::value_type balance, balances)
|
||||
{
|
||||
json_spirit::Object addressInfo;
|
||||
addressInfo.push_back(json_spirit::Pair("address",CBitcoinAddress(balance.first).ToString()));
|
||||
addressInfo.push_back(json_spirit::Pair("balance", ValueFromAmount(balance.second)));
|
||||
addressBalanceArray.push_back(addressInfo);
|
||||
}
|
||||
result.push_back(json_spirit::Pair("addresses", addressBalanceArray));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
// send result to out queue
|
||||
WalletServerSession::sendMessageToQueue(outputJson);
|
||||
return outputJson;
|
||||
}
|
||||
|
||||
json_spirit::Value WalletServerSession::sendCoinsToAddress(Command data)
|
||||
{
|
||||
std::string strAddress = "";
|
||||
std::string strAmount = "";
|
||||
std::string strComment = "";
|
||||
// loop over arguments and get the values
|
||||
std::map<std::string, std::string>::iterator argit;
|
||||
for(argit = data.arguments.begin(); argit != data.arguments.end(); argit++) {
|
||||
if(argit->first.compare("address")==0)
|
||||
strAddress = argit->second;
|
||||
else if(argit->first.compare("amount")==0)
|
||||
strAmount = argit->second;
|
||||
else if(argit->first.compare("comment")==0)
|
||||
strComment = argit->second;
|
||||
}
|
||||
printf("WalletServerSession: %s sendCoinsToAddress: %s Amount: %s\n", sessionId.c_str(), strAddress.c_str(), strAmount.c_str());
|
||||
// define output object
|
||||
json_spirit::Object outputJson;
|
||||
outputJson.push_back(json_spirit::Pair("sessionid", sessionId));
|
||||
outputJson.push_back(json_spirit::Pair("correlationid", data.correlationId));
|
||||
outputJson.push_back(json_spirit::Pair("command", data.command));
|
||||
// create coin address
|
||||
CBitcoinAddress address(strAddress);
|
||||
if (!address.IsValid())
|
||||
{
|
||||
// send error message
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 111));
|
||||
result.push_back(json_spirit::Pair("errorMessage", "Invalid CasinoCoin address."));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
// send result to out queue
|
||||
WalletServerSession::sendMessageToQueue(outputJson);
|
||||
return outputJson;
|
||||
}
|
||||
// Amount
|
||||
int64 nAmount;
|
||||
ParseMoney(strAmount, nAmount);
|
||||
if (nAmount <= 0)
|
||||
{
|
||||
// send error message
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 112));
|
||||
result.push_back(json_spirit::Pair("errorMessage", "Amount of coins to sent to address must be greater than 0."));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
// send result to out queue
|
||||
WalletServerSession::sendMessageToQueue(outputJson);
|
||||
return outputJson;
|
||||
}
|
||||
// Wallet comments
|
||||
CWalletTx wtx;
|
||||
if(!strComment.empty())
|
||||
wtx.mapValue["comment"] = strComment;
|
||||
// check if wallet is locked
|
||||
// if (pwalletMain->IsLocked())
|
||||
// throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
|
||||
// execute send
|
||||
string strError = clientWallet->SendMoneyToDestination(address.Get(), nAmount, wtx);
|
||||
if (strError != "")
|
||||
{
|
||||
// send error message
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 10));
|
||||
result.push_back(json_spirit::Pair("errorMessage", "Error sending coins: " + strError));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
}
|
||||
else
|
||||
{
|
||||
json_spirit::Object result;
|
||||
result.push_back(json_spirit::Pair("errorCode", 0));
|
||||
result.push_back(json_spirit::Pair("errorMessage", ""));
|
||||
result.push_back(json_spirit::Pair("txid", wtx.GetHash().GetHex()));
|
||||
outputJson.push_back(json_spirit::Pair("result", result));
|
||||
}
|
||||
// send result to out queue
|
||||
WalletServerSession::sendMessageToQueue(outputJson);
|
||||
return outputJson;
|
||||
}
|
||||
|
||||
void WalletServerSession::closeSession()
|
||||
{
|
||||
printf("WalletServerSession sessionId: %s Execute closeSession\n", sessionId.c_str());
|
||||
closeWalletIfOpen();
|
||||
// remove wallet object
|
||||
if(clientWallet != NULL)
|
||||
delete clientWallet;
|
||||
// set shutdownComplete
|
||||
shutdownComplete = true;
|
||||
printf("WalletServerSession sessionId: %s Session Close Finished!\n", sessionId.c_str());
|
||||
}
|
||||
95
src/walletserversession.h
Normal file
95
src/walletserversession.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#ifndef WALLETSERVERSESSION_H
|
||||
#define WALLETSERVERSESSION_H
|
||||
|
||||
#include <string>
|
||||
#include "walletserver.h"
|
||||
#include "wallet.h"
|
||||
#include "json/json_spirit.h"
|
||||
#include "stomp/booststomp.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
typedef std::map<CTxDestination, int64> balancesMapType;
|
||||
|
||||
// Class that consumes objects from a queue
|
||||
class WalletServerSession
|
||||
{
|
||||
private:
|
||||
SynchronisedCommandQueue<Command>* m_queue; // The queue to use
|
||||
std::string sessionId; // The id of the wallet session
|
||||
std::string walletId; // The wallet id of the session
|
||||
boost::filesystem::path walletFilename;
|
||||
// ActiveMQ Connection
|
||||
STOMP::BoostStomp* session_stomp_client;
|
||||
// Wallet
|
||||
CWallet* clientWallet;
|
||||
bool walletOpen;
|
||||
// Handle new block signal
|
||||
void NotifyBlocksChanged();
|
||||
// Handle new transaction signal
|
||||
void NotifyTransactionChanged(CWallet *wallet, const uint256 &hash, ChangeType status);
|
||||
// shutdown condition
|
||||
bool shutdownComplete;
|
||||
|
||||
// wallet commands
|
||||
void openWallet(Command data);
|
||||
void closeWallet(Command data);
|
||||
json_spirit::Value getWalletInfo(Command data);
|
||||
json_spirit::Value getAddressBook(Command data);
|
||||
json_spirit::Value sendCoinsToAddress(Command data);
|
||||
|
||||
public:
|
||||
// Constructor with id and the queue to use.
|
||||
WalletServerSession(std::string newSessionId, SynchronisedCommandQueue<Command>* queue);
|
||||
// Destructor
|
||||
~WalletServerSession();
|
||||
|
||||
// Default operator that starts the ActiveMQ connection and reads data from the WalletServer queue
|
||||
void operator () ()
|
||||
{
|
||||
printf("WalletServerSession - ActiveMQ connection for session: %s\n", sessionId.c_str());
|
||||
// initialize wallet pointer to NULL
|
||||
clientWallet = NULL;
|
||||
shutdownComplete = false;
|
||||
// initiate a new BoostStomp client
|
||||
session_stomp_client = new STOMP::BoostStomp(WalletServer::stomp_host, WalletServer::stomp_port);
|
||||
session_stomp_client->enable_debug_msgs(false);
|
||||
// start the client, (by connecting to the STOMP server)
|
||||
session_stomp_client->start();
|
||||
// connect to Signals
|
||||
uiInterface.NotifyBlocksChanged.connect(boost::bind(&WalletServerSession::NotifyBlocksChanged, this));
|
||||
printf("WalletServerSession - Start Dequeue for session: %s\n", sessionId.c_str());
|
||||
while (true)
|
||||
{
|
||||
// Get the data from the queue and print it
|
||||
Command data = m_queue->Dequeue();
|
||||
printf("Consumer Session: %s consumed: %s for session: %s ThreadID: %s\n",
|
||||
sessionId.c_str(), data.command.c_str(), data.sessionId.c_str(),
|
||||
boost::lexical_cast<std::string>(boost::this_thread::get_id()).c_str());
|
||||
executeWalletCommand(data);
|
||||
// if closesesion command then wait for shutdown complete
|
||||
if(data.command.compare("closesession") == 0)
|
||||
{
|
||||
while(!shutdownComplete)
|
||||
{
|
||||
printf("Wait until closesession shutdownComplete");
|
||||
MilliSleep(100);
|
||||
}
|
||||
}
|
||||
// Make sure we can be interrupted
|
||||
boost::this_thread::interruption_point();
|
||||
}
|
||||
}
|
||||
|
||||
// public methods
|
||||
void sendMessageToQueue(json_spirit::Object outputJson);
|
||||
void executeWalletCommand(Command data);
|
||||
void closeWalletIfOpen();
|
||||
void setWalletOpen();
|
||||
bool isWalletOpen();
|
||||
void closeSession();
|
||||
};
|
||||
|
||||
#endif // WALLETSERVERSESSION_H
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
; HM NIS Edit Wizard helper defines
|
||||
!define PRODUCT_NAME "Casinocoin Wallet"
|
||||
!define PRODUCT_VERSION "2.0.0.0"
|
||||
!define PRODUCT_VERSION "2.0.1.0"
|
||||
!define PRODUCT_PUBLISHER "Casinocoin"
|
||||
!define PRODUCT_WEB_SITE "http://www.casinocoin.org"
|
||||
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\casinocoin-qt.exe"
|
||||
@@ -47,7 +47,7 @@ var ICONS_GROUP
|
||||
; MUI end ------
|
||||
|
||||
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
|
||||
OutFile "release\casinocoin-2.0.0.0-setup.exe"
|
||||
OutFile "release\casinocoin-2.0.1.0-setup.exe"
|
||||
InstallDir "$PROGRAMFILES\Casinocoin"
|
||||
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
|
||||
ShowInstDetails show
|
||||
@@ -76,6 +76,7 @@ Section "MainSection" SEC01
|
||||
File "release\plugins\imageformats\qwebp.dll"
|
||||
SetOutPath "$INSTDIR\plugins\platforms"
|
||||
File "release\plugins\platforms\qwindows.dll"
|
||||
File "release\plugins\platforms\qminimal.dll"
|
||||
SetOutPath "$INSTDIR\qml\QtQml\Models.2"
|
||||
File "release\qml\QtQml\Models.2\modelsplugin.dll"
|
||||
File "release\qml\QtQml\Models.2\plugins.qmltypes"
|
||||
@@ -658,6 +659,7 @@ Section Uninstall
|
||||
Delete "$INSTDIR\qml\QtQml\Models.2\plugins.qmltypes"
|
||||
Delete "$INSTDIR\qml\QtQml\Models.2\modelsplugin.dll"
|
||||
Delete "$INSTDIR\plugins\platforms\qwindows.dll"
|
||||
Delete "$INSTDIR\plugins\platforms\qminimal.dll"
|
||||
Delete "$INSTDIR\plugins\imageformats\qwebp.dll"
|
||||
Delete "$INSTDIR\plugins\imageformats\qwbmp.dll"
|
||||
Delete "$INSTDIR\plugins\imageformats\qtiff.dll"
|
||||
|
||||
Reference in New Issue
Block a user