초기커밋
This commit is contained in:
397
ServerBase/Entity/Attribute/EntityAttributeBase.cs
Normal file
397
ServerBase/Entity/Attribute/EntityAttributeBase.cs
Normal file
@@ -0,0 +1,397 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using NeoSmart;
|
||||
using NeoSmart.AsyncLock;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_ID = System.UInt32;
|
||||
using META_ID = System.UInt32;
|
||||
using ENTITY_GUID = System.String;
|
||||
using ACCOUNT_ID = System.String;
|
||||
using OWNER_GUID = System.String;
|
||||
using USER_GUID = System.String;
|
||||
using CHARACTER_GUID = System.String;
|
||||
using ITEM_GUID = System.String;
|
||||
|
||||
|
||||
namespace ServerBase;
|
||||
|
||||
|
||||
public abstract partial class EntityAttributeBase : IInitializer
|
||||
{
|
||||
public enum StateType
|
||||
{
|
||||
None = 0,
|
||||
|
||||
Created, // 신규 정보로 추가 한다. delta count == Stack count !!!
|
||||
Modified, // +, - : 증가, 감소
|
||||
Removed, // 제거
|
||||
}
|
||||
|
||||
public class AttributeState : Flags<StateType>
|
||||
{
|
||||
public AttributeState()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
public void tryApplyModifyFlag(bool isTrue)
|
||||
{
|
||||
setFlag(StateType.Modified, isTrue);
|
||||
}
|
||||
}
|
||||
|
||||
#region 소유자라고 설정한 객체
|
||||
private EntityBase m_owner;
|
||||
#endregion
|
||||
|
||||
private bool m_is_origin = true;
|
||||
|
||||
private DynamoDbDocBase? m_origin_doc_base_nullable;
|
||||
|
||||
private DynamoDbDocBase? m_try_pending_doc_base_nullable;
|
||||
|
||||
// CommonResult에 적용 되는가?
|
||||
private readonly bool m_is_applicable_to_common_result;
|
||||
|
||||
private AttributeState m_attribute_state = new();
|
||||
|
||||
private bool m_is_upsert = false;
|
||||
|
||||
private bool m_is_delete = false;
|
||||
|
||||
private EntityRecorder? m_recorder_nullable;
|
||||
|
||||
#region Owner Contents 관계에 맞게 저장되는 소유자 정보[OwnerEntityType, EntityBase]
|
||||
private OwnerEntityType m_owner_entity_type = OwnerEntityType.None;
|
||||
private EntityBase? m_entity_of_owner_entity_type = null;
|
||||
#endregion
|
||||
|
||||
private ReaderWriterLockSlim m_rw_lock = new();
|
||||
|
||||
private AsyncLock m_async_lock = new();
|
||||
|
||||
//=========================================================================================
|
||||
// Owner 객체와 OwnerEntityType 객체가 동일한 경우
|
||||
//=========================================================================================
|
||||
public EntityAttributeBase(EntityBase owner, bool isApplicableCommonResult = false)
|
||||
{
|
||||
m_owner = owner;
|
||||
|
||||
setEntityOfOwnerEntityType(owner.onGetOwnerEntityType(), owner);
|
||||
|
||||
m_is_applicable_to_common_result = isApplicableCommonResult;
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
// Owner 객체와 OwnerEntityType 객체가 다른 경우
|
||||
//=========================================================================================
|
||||
public EntityAttributeBase(EntityBase owner, EntityBase entityOfOwnerEntityType, bool isApplicableCommonResult = false)
|
||||
{
|
||||
if(false == entityOfOwnerEntityType.isValidOwnerEntityType())
|
||||
{
|
||||
throw new ArgumentException($"argument exception isValidOwnerEntityType() !!! : {entityOfOwnerEntityType.toBasicString()} - {toBasicString()}");
|
||||
}
|
||||
|
||||
m_owner = owner;
|
||||
|
||||
setEntityOfOwnerEntityType(entityOfOwnerEntityType.onGetOwnerEntityType(), entityOfOwnerEntityType);
|
||||
|
||||
m_is_applicable_to_common_result = isApplicableCommonResult;
|
||||
}
|
||||
|
||||
public virtual async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public abstract void onClear();
|
||||
|
||||
public virtual void newEntityAttribute()
|
||||
{
|
||||
getAttributeState().setFlag(StateType.Created, true);
|
||||
}
|
||||
|
||||
public virtual void deleteEntityAttribute()
|
||||
{
|
||||
getAttributeState().reset();
|
||||
m_is_upsert = false;
|
||||
|
||||
getAttributeState().setFlag(StateType.Removed, true);
|
||||
}
|
||||
|
||||
public virtual void modifiedEntityAttribute(bool isUpsert = false)
|
||||
{
|
||||
if (true == getAttributeState().hasFlag(StateType.Created))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
getAttributeState().setFlag(StateType.Modified, true);
|
||||
if(true == isUpsert)
|
||||
{
|
||||
m_is_upsert = isUpsert;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract IEntityAttributeTransactor onNewEntityAttributeTransactor();
|
||||
|
||||
public abstract EntityAttributeBase onCloned();
|
||||
|
||||
|
||||
|
||||
protected void deepCopyFromBase(EntityAttributeBase other)
|
||||
{
|
||||
m_attribute_state.deepCopy(other.getAttributeState());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public virtual DynamoDbDocBase? onCreateDocBase()
|
||||
{
|
||||
var err_msg = $"Not implementation EntityAttribute.onCreateDocBase() !!! : {this.getTypeName()} - {getOwner().toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
throw new NotImplementedException(err_msg);
|
||||
}
|
||||
|
||||
public virtual async Task<(Result, DynamoDbDocBase?)> toDocBase(bool isForQuery = true)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var err_msg = $"Not implementation EntityAttribute.toDocBase() !!! : {this.getTypeName()} - {getOwner().toBasicString()}";
|
||||
result.setFail(ServerErrorCode.NotImplemented, err_msg);
|
||||
Log.getLogger().warn(result.toBasicString());
|
||||
|
||||
return await Task.FromResult<(Result, DynamoDbDocBase?)>((result, null));
|
||||
}
|
||||
|
||||
public virtual async Task<Result> fillupDocBase<TDoc>(TDoc copyToDocBase)
|
||||
where TDoc : DynamoDbDocBase
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var owner = getOwner();
|
||||
var parent = owner.getRootParent();
|
||||
|
||||
var copy_to_doc = copyToDocBase as ICopyDocFromEntityAttribute;
|
||||
if(null == copy_to_doc)
|
||||
{
|
||||
err_msg = $"Failed to cast ICopyDocFromEntityAttribute !!! : {copyToDocBase.getTypeName()} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ClassDoesNotImplementInterfaceInheritance, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if(false == copy_to_doc.copyDocFromEntityAttribute(this))
|
||||
{
|
||||
err_msg = $"Failed to copyDocFromEntityAttribute() !!!, to:{copyToDocBase.getTypeName()}, from:{this.getTypeName()} - {toSummaryString()}, {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public async Task<Result> fillupDoc4QueryWithAttribute<TDoc>(TDoc docBase)
|
||||
where TDoc : DynamoDbDocBase
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var owner = getOwner();
|
||||
var parent = owner.getRootParent();
|
||||
|
||||
result = await fillupDocBase<TDoc>(docBase);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to fillupDocBase() !!! : {result.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
(result, _) = await applyDoc4Query(docBase);
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected async Task<(Result, DynamoDbDocBase?)> applyDoc4Query(DynamoDbDocBase docBase)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var owner = getOwner();
|
||||
var parent = owner.getRootParent();
|
||||
|
||||
bool is_apply = false;
|
||||
|
||||
if (true == getAttributeState().hasFlag(StateType.Created))
|
||||
{
|
||||
result = await docBase.newDoc4Query();
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
is_apply = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (true == getAttributeState().hasFlag(StateType.Modified))
|
||||
{
|
||||
if (true == m_is_upsert)
|
||||
{
|
||||
result = await docBase.upsertDoc4Query();
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await docBase.updateDoc4Query();
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
}
|
||||
|
||||
m_is_upsert = false;
|
||||
is_apply = true;
|
||||
}
|
||||
|
||||
if (true == getAttributeState().hasFlag(StateType.Removed))
|
||||
{
|
||||
result = await docBase.deleteDoc4Query();
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
is_apply = true;
|
||||
|
||||
setDelete();
|
||||
}
|
||||
}
|
||||
|
||||
if (false == is_apply)
|
||||
{
|
||||
err_msg = $"Invalid AttributeState !!!, all false state - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocAttributeStateNotSet, err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
getAttributeState().reset();
|
||||
|
||||
return (result, docBase);
|
||||
}
|
||||
|
||||
public void enterReadLock()
|
||||
{
|
||||
m_rw_lock.EnterReadLock();
|
||||
}
|
||||
|
||||
public void exitReadLock()
|
||||
{
|
||||
m_rw_lock.ExitReadLock();
|
||||
}
|
||||
|
||||
public void enterWriteLock()
|
||||
{
|
||||
m_rw_lock.EnterWriteLock();
|
||||
}
|
||||
|
||||
public void exitWriteLock()
|
||||
{
|
||||
m_rw_lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
public bool hasQueryFlag()
|
||||
{
|
||||
return 0 < getAttributeState().getData().Count;
|
||||
}
|
||||
|
||||
#region DB 저장과 관련된 함수들
|
||||
|
||||
//=================================================================================================
|
||||
// EntityAttribute로 Db에 저장할 OwnerEntity를 반환해 준다.
|
||||
//=================================================================================================
|
||||
public virtual (Result, OwnerEntityType, OWNER_GUID) onToOwnerEntity4Db(EntityBase ownerEntity)
|
||||
{
|
||||
var result = new Result();
|
||||
result.setFail(ServerErrorCode.NotImplemented, $"Not implemented onToOwnerEntity4Db() !!! - {getOwner().toBasicString()}");
|
||||
|
||||
return (result, OwnerEntityType.None, string.Empty);
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
// DB 에 저장되어 있는 정보가 있는 경우 호출되어야 한다.
|
||||
//=========================================================================================
|
||||
public void syncOriginDocBaseWithNewDoc<EntityAttributeType>(DynamoDbDocBase newDoc)
|
||||
where EntityAttributeType : EntityAttributeBase
|
||||
{
|
||||
if(true == isOrigin())
|
||||
{
|
||||
m_origin_doc_base_nullable = newDoc;
|
||||
return;
|
||||
}
|
||||
|
||||
var owner = getOwner();
|
||||
var origin_entity_attribute = owner.getOriginEntityAttribute<EntityAttributeType>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_entity_attribute, () => $"origin_entity_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
origin_entity_attribute.syncOriginDocBaseWithNewDoc<EntityAttributeType>(newDoc);
|
||||
}
|
||||
|
||||
public DynamoDbDocBase? getOriginDocBase<EntityAttributeType>()
|
||||
where EntityAttributeType : EntityAttributeBase
|
||||
{
|
||||
if (true == isOrigin())
|
||||
{
|
||||
return m_origin_doc_base_nullable;
|
||||
}
|
||||
|
||||
var owner = getOwner();
|
||||
var origin_entity_attribute = owner.getOriginEntityAttribute<EntityAttributeType>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_entity_attribute, () => $"origin_entity_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
return origin_entity_attribute.getOriginDocBase<EntityAttributeType>();
|
||||
}
|
||||
|
||||
#endregion DB 저장과 관련된 함수들
|
||||
|
||||
|
||||
#region 로그와 관련된 함수들
|
||||
|
||||
public virtual string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}, {JsonConvert.SerializeObject(this)}";
|
||||
}
|
||||
|
||||
public virtual string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}, isOrigin:{isOrigin()}, hasQueryFlag:{hasQueryFlag()}";
|
||||
}
|
||||
|
||||
#endregion 로그와 관련된 함수들
|
||||
}
|
||||
113
ServerBase/Entity/Attribute/EntityAttributeTransactorBase.cs
Normal file
113
ServerBase/Entity/Attribute/EntityAttributeTransactorBase.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_ID = System.UInt32;
|
||||
using META_ID = System.UInt32;
|
||||
using ENTITY_GUID = System.String;
|
||||
using ACCOUNT_ID = System.String;
|
||||
using OWNER_GUID = System.String;
|
||||
using USER_GUID = System.String;
|
||||
using CHARACTER_GUID = System.String;
|
||||
using ITEM_GUID = System.String;
|
||||
|
||||
|
||||
|
||||
namespace ServerBase;
|
||||
|
||||
public abstract partial class EntityAttributeTransactorBase<TEntityAttribute> : IEntityAttributeTransactor
|
||||
where TEntityAttribute : EntityAttributeBase
|
||||
{
|
||||
public enum TransactionState
|
||||
{
|
||||
None = 0,
|
||||
|
||||
New, // 생성
|
||||
Modify, // 변경
|
||||
Remove, // 제거
|
||||
|
||||
Completed // 처리 완료
|
||||
}
|
||||
|
||||
private EntityBase m_owner;
|
||||
|
||||
private TEntityAttribute? m_cloned_entity_attribute_nullable;
|
||||
|
||||
private TransactionState m_transaction_state = TransactionState.None;
|
||||
|
||||
private readonly EntityRecorder m_entity_recorder;
|
||||
|
||||
private TEntityAttribute? m_origin_entity_attribute_nullable;
|
||||
|
||||
|
||||
public EntityAttributeTransactorBase(EntityBase owner)
|
||||
{
|
||||
m_owner = owner;
|
||||
m_entity_recorder = new EntityRecorder(owner);
|
||||
}
|
||||
|
||||
public bool cloneFromOriginEntityAttribute(EntityAttributeBase fromOriginEntityAttribute)
|
||||
{
|
||||
m_cloned_entity_attribute_nullable = fromOriginEntityAttribute.onCloned() as TEntityAttribute;
|
||||
if(null == m_cloned_entity_attribute_nullable)
|
||||
{
|
||||
var err_msg = $"m_cloned_entity_attribute_nullable is null !!! : toCloneTarget:{typeof(TEntityAttribute).Name} != OriginEntityAttribute:{fromOriginEntityAttribute.getTypeName()} - {getOwner().toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_cloned_entity_attribute_nullable.setCloned();
|
||||
m_cloned_entity_attribute_nullable.bindEntityRecorder(m_entity_recorder);
|
||||
|
||||
m_origin_entity_attribute_nullable = fromOriginEntityAttribute as TEntityAttribute;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool isReadOnly()
|
||||
{
|
||||
NullReferenceCheckHelper.throwIfNull(m_cloned_entity_attribute_nullable, () => $"m_cloned_entity_attribute_nullable is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
if(true == m_cloned_entity_attribute_nullable.getAttributeState().isEmptyFlags())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<(Result, DynamoDbDocBase?)> makeDocBase()
|
||||
{
|
||||
NullReferenceCheckHelper.throwIfNull(m_cloned_entity_attribute_nullable, () => $"m_cloned_entity_attribute_nullable is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
(var result, var doc) = await m_cloned_entity_attribute_nullable.toDocBase();
|
||||
if(result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, doc);
|
||||
}
|
||||
|
||||
public virtual void onClear()
|
||||
{
|
||||
m_cloned_entity_attribute_nullable?.onClear();
|
||||
|
||||
m_entity_recorder.reset();
|
||||
}
|
||||
|
||||
public ENTITY_GUID getEntityGuid() => getOwner().getEntityGuid();
|
||||
|
||||
public virtual string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}, {m_cloned_entity_attribute_nullable?.toBasicString()}, {getOwner().toBasicString()}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user