login: account creation/retrieval is working
This commit is contained in:
parent
140f520d65
commit
45b178a729
7 changed files with 189 additions and 17 deletions
1
astron/databases/.gitignore
vendored
Normal file
1
astron/databases/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.db
|
1
astron/databases/astrondb/.gitignore
vendored
Normal file
1
astron/databases/astrondb/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.yaml
|
11
etc/otp.dc
11
etc/otp.dc
|
@ -4,6 +4,7 @@ from direct.distributed import DistributedSmoothNode/AI
|
||||||
from direct.distributed import DistributedCartesianGrid/AI
|
from direct.distributed import DistributedCartesianGrid/AI
|
||||||
from direct.distributed import DistributedCamera/AI/OV
|
from direct.distributed import DistributedCamera/AI/OV
|
||||||
from otp.distributed import Account/AI/UD
|
from otp.distributed import Account/AI/UD
|
||||||
|
from otp.distributed import AstronAccount/AI/UD
|
||||||
from otp.ai import TimeManager/AI
|
from otp.ai import TimeManager/AI
|
||||||
from otp.ai import MagicWordManager/AI
|
from otp.ai import MagicWordManager/AI
|
||||||
from otp.avatar import DistributedAvatar/AI/UD
|
from otp.avatar import DistributedAvatar/AI/UD
|
||||||
|
@ -53,6 +54,15 @@ dclass Account {
|
||||||
string LAST_LOGIN db;
|
string LAST_LOGIN db;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dclass AstronAccount {
|
||||||
|
uint32[] ACCOUNT_AV_SET required db;
|
||||||
|
uint32 ESTATE_ID db;
|
||||||
|
AvatarPendingDel ACCOUNT_AV_SET_DEL[] db;
|
||||||
|
string CREATED db;
|
||||||
|
string LAST_LOGIN db;
|
||||||
|
string ACCOUNT_ID db;
|
||||||
|
};
|
||||||
|
|
||||||
struct BarrierData {
|
struct BarrierData {
|
||||||
uint16 context;
|
uint16 context;
|
||||||
string name;
|
string name;
|
||||||
|
@ -515,4 +525,3 @@ dclass AstronLoginManager : DistributedObject {
|
||||||
requestLogin(string) clsend;
|
requestLogin(string) clsend;
|
||||||
loginResponse(blob);
|
loginResponse(blob);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
6
otp/distributed/AstronAccount.py
Normal file
6
otp/distributed/AstronAccount.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from direct.distributed import DistributedObject
|
||||||
|
|
||||||
|
class AstronAccount(DistributedObject.DistributedObject):
|
||||||
|
|
||||||
|
def __init__(self, cr):
|
||||||
|
pass
|
5
otp/distributed/AstronAccountAI.py
Normal file
5
otp/distributed/AstronAccountAI.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from direct.directnotify import DirectNotifyGlobal
|
||||||
|
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
||||||
|
|
||||||
|
class AstronAccountAI(DistributedObjectAI):
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('AstronAccountAI')
|
5
otp/distributed/AstronAccountUD.py
Normal file
5
otp/distributed/AstronAccountUD.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from direct.directnotify import DirectNotifyGlobal
|
||||||
|
from direct.distributed.DistributedObjectUD import DistributedObjectUD
|
||||||
|
|
||||||
|
class AstronAccountUD(DistributedObjectUD):
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('AstronAccountUD')
|
|
@ -1,34 +1,179 @@
|
||||||
|
import anydbm
|
||||||
|
import dumbdbm
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
from direct.directnotify import DirectNotifyGlobal
|
from direct.directnotify import DirectNotifyGlobal
|
||||||
from direct.distributed.DistributedObjectGlobalUD import DistributedObjectGlobalUD
|
from direct.distributed.DistributedObjectGlobalUD import DistributedObjectGlobalUD
|
||||||
from direct.distributed.PyDatagram import *
|
from direct.distributed.PyDatagram import *
|
||||||
|
|
||||||
class AstronLoginManagerUD(DistributedObjectGlobalUD):
|
class AccountDB:
|
||||||
notify = DirectNotifyGlobal.directNotify.newCategory('AstronLoginManagerUD')
|
"""
|
||||||
|
AccountDB is the base class for all account database interface implementations.
|
||||||
|
"""
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('AccountDB')
|
||||||
|
|
||||||
def requestLogin(self, playToken):
|
def __init__(self, loginManager):
|
||||||
# TODO SET THIS UP PROPERLY.
|
self.loginManager = loginManager
|
||||||
# AT THE MOMENT EVERYTHING IS HARDCODED
|
|
||||||
# THIS IS JUST TO GET TO THE PICK A TOON SCREEN
|
|
||||||
|
|
||||||
# get the sender
|
# Setup the dbm:
|
||||||
sender = self.air.getMsgSender()
|
accountDbFile = config.GetString('accountdb-local-file', 'astron/databases/accounts.db')
|
||||||
|
if sys.platform == 'darwin': # macOS
|
||||||
|
dbm = dumbdbm
|
||||||
|
else:
|
||||||
|
dbm = anydbm
|
||||||
|
|
||||||
|
self.dbm = dbm.open(accountDbFile, 'c')
|
||||||
|
|
||||||
|
def lookup(self, playToken, callback):
|
||||||
|
raise NotImplementedError('lookup') # Must be overridden by subclass.
|
||||||
|
|
||||||
|
def storeAccountId(self, databaseId, accountId, callback):
|
||||||
|
self.dbm[databaseId] = str(accountId)
|
||||||
|
if hasattr(self.dbm, 'sync') and self.dbm.sync:
|
||||||
|
self.dbm.sync()
|
||||||
|
callback(True)
|
||||||
|
else:
|
||||||
|
self.notify.warning('Unable to associate user %s with account %s!' % (databaseId, accountId))
|
||||||
|
callback(False)
|
||||||
|
|
||||||
|
|
||||||
|
class DeveloperAccountDB(AccountDB):
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('DeveloperAccountDB')
|
||||||
|
|
||||||
|
def lookup(self, playToken, callback):
|
||||||
|
# Check if this play token exists in the dbm:
|
||||||
|
if str(playToken) not in self.dbm:
|
||||||
|
# It is not, so we'll associate them with a brand new account object.
|
||||||
|
callback({'success': True,
|
||||||
|
'accountId': 0,
|
||||||
|
'databaseId': playToken})
|
||||||
|
else:
|
||||||
|
# We already have an account object, so we'll just return what we have.
|
||||||
|
callback({'success': True,
|
||||||
|
'accountId': int(self.dbm[playToken]),
|
||||||
|
'databaseId': playToken})
|
||||||
|
|
||||||
|
|
||||||
|
class LoginOperation:
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('LoginOperation')
|
||||||
|
|
||||||
|
def __init__(self, loginManager, sender):
|
||||||
|
self.loginManager = loginManager
|
||||||
|
self.sender = sender
|
||||||
|
self.playToken = ''
|
||||||
|
self.databaseId = 0
|
||||||
|
self.accountId = 0
|
||||||
|
self.account = None
|
||||||
|
|
||||||
|
def start(self, playToken):
|
||||||
|
self.playToken = playToken
|
||||||
|
self.loginManager.accountDb.lookup(playToken, self.__handleLookup)
|
||||||
|
|
||||||
|
def __handleLookup(self, result):
|
||||||
|
if not result.get('success'):
|
||||||
|
# TODO: Kill the connection
|
||||||
|
return
|
||||||
|
|
||||||
|
self.databaseId = result.get('databaseId', 0)
|
||||||
|
accountId = result.get('accountId', 0)
|
||||||
|
if accountId:
|
||||||
|
self.accountId = accountId
|
||||||
|
self.__handleRetrieveAccount()
|
||||||
|
else:
|
||||||
|
self.__handleCreateAccount()
|
||||||
|
|
||||||
|
def __handleRetrieveAccount(self):
|
||||||
|
self.loginManager.air.dbInterface.queryObject(self.loginManager.air.dbId, self.accountId, self.__handleAccountRetrieved)
|
||||||
|
|
||||||
|
def __handleAccountRetrieved(self, dclass, fields):
|
||||||
|
if dclass != self.loginManager.air.dclassesByName['AstronAccountUD']:
|
||||||
|
print 'no uwu'
|
||||||
|
return
|
||||||
|
|
||||||
|
self.account = fields
|
||||||
|
self.__handleSetAccount()
|
||||||
|
|
||||||
|
def __handleCreateAccount(self):
|
||||||
|
self.account = {'ACCOUNT_AV_SET': [0] * 6,
|
||||||
|
'ESTATE_ID': 0,
|
||||||
|
'ACCOUNT_AV_SET_DEL': [],
|
||||||
|
'CREATED': time.ctime(),
|
||||||
|
'LAST_LOGIN': time.ctime(),
|
||||||
|
'ACCOUNT_ID': str(self.databaseId)}
|
||||||
|
|
||||||
|
self.loginManager.air.dbInterface.createObject(self.loginManager.air.dbId, self.loginManager.air.dclassesByName['AstronAccountUD'], self.account, self.__handleAccountCreated)
|
||||||
|
|
||||||
|
def __handleAccountCreated(self, accountId):
|
||||||
|
if not accountId:
|
||||||
|
# FAILURE!!!!!
|
||||||
|
return
|
||||||
|
|
||||||
|
self.accountId = accountId
|
||||||
|
self.__storeAccountId()
|
||||||
|
|
||||||
|
def __storeAccountId(self):
|
||||||
|
self.loginManager.accountDb.storeAccountId(self.databaseId, self.accountId, self.__handleAccountIdStored)
|
||||||
|
|
||||||
|
def __handleAccountIdStored(self, success=True):
|
||||||
|
if not success:
|
||||||
|
# FAILURE!!!!!!!!!!!!
|
||||||
|
return
|
||||||
|
|
||||||
|
self.__handleSetAccount()
|
||||||
|
|
||||||
|
def __handleSetAccount(self):
|
||||||
|
# if somebody's already logged into this account, disconnect them
|
||||||
|
datagram = PyDatagram()
|
||||||
|
datagram.addServerHeader(self.loginManager.GetAccountConnectionChannel(self.accountId), self.loginManager.air.ourChannel, CLIENTAGENT_EJECT)
|
||||||
|
datagram.addUint16(100)
|
||||||
|
datagram.addString('This account has been logged in elsewhere.')
|
||||||
|
self.loginManager.air.send(datagram)
|
||||||
|
|
||||||
# add connection to account channel
|
# add connection to account channel
|
||||||
datagram = PyDatagram()
|
datagram = PyDatagram()
|
||||||
datagram.addServerHeader(sender, self.air.ourChannel, CLIENTAGENT_OPEN_CHANNEL)
|
datagram.addServerHeader(self.sender, self.loginManager.air.ourChannel, CLIENTAGENT_OPEN_CHANNEL)
|
||||||
datagram.addChannel(self.GetAccountConnectionChannel(1000000000))
|
datagram.addChannel(self.loginManager.GetAccountConnectionChannel(self.accountId))
|
||||||
self.air.send(datagram)
|
self.loginManager.air.send(datagram)
|
||||||
|
|
||||||
# set sender channel to represent account affiliation
|
# set sender channel to represent account affiliation
|
||||||
datagram = PyDatagram()
|
datagram = PyDatagram()
|
||||||
datagram.addServerHeader(sender, self.air.ourChannel, CLIENTAGENT_SET_CLIENT_ID)
|
datagram.addServerHeader(self.sender, self.loginManager.air.ourChannel, CLIENTAGENT_SET_CLIENT_ID)
|
||||||
datagram.addChannel(1000000000 << 32) # accountId is in high 32 bits, 0 in low (no avatar).
|
datagram.addChannel(self.accountId << 32) # accountId is in high 32 bits, 0 in low (no avatar).
|
||||||
self.air.send(datagram)
|
self.loginManager.air.send(datagram)
|
||||||
|
|
||||||
# set client state to established, thus un-sandboxing the sender
|
# set client state to established, thus un-sandboxing the sender
|
||||||
self.air.setClientState(sender, 2)
|
self.loginManager.air.setClientState(self.sender, 2)
|
||||||
|
|
||||||
# send dummy login response
|
# send dummy login response
|
||||||
import json
|
import json
|
||||||
a = json.dumps({})
|
a = json.dumps({})
|
||||||
self.sendUpdateToChannel(sender, 'loginResponse', [a])
|
self.loginManager.sendUpdateToChannel(self.sender, 'loginResponse', [a])
|
||||||
|
|
||||||
|
|
||||||
|
class AstronLoginManagerUD(DistributedObjectGlobalUD):
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('AstronLoginManagerUD')
|
||||||
|
|
||||||
|
def __init__(self, air):
|
||||||
|
DistributedObjectGlobalUD.__init__(self, air)
|
||||||
|
self.accountDb = None
|
||||||
|
self.sender2loginOperation = {}
|
||||||
|
|
||||||
|
def announceGenerate(self):
|
||||||
|
DistributedObjectGlobalUD.announceGenerate(self)
|
||||||
|
|
||||||
|
# Instantiate the account database backend.
|
||||||
|
# TODO: In the future, add more database interfaces & make this configurable.
|
||||||
|
self.accountDb = DeveloperAccountDB(self)
|
||||||
|
|
||||||
|
def requestLogin(self, playToken):
|
||||||
|
# Get the connection ID:
|
||||||
|
sender = self.air.getMsgSender()
|
||||||
|
|
||||||
|
if sender in self.sender2loginOperation.keys():
|
||||||
|
# BAD!!!!
|
||||||
|
return
|
||||||
|
|
||||||
|
newLoginOperation = LoginOperation(self, sender)
|
||||||
|
self.sender2loginOperation[sender] = newLoginOperation
|
||||||
|
newLoginOperation.start(playToken)
|
||||||
|
|
Loading…
Reference in a new issue