Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
C
courier
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张宇
courier
Commits
bad15ffe
Commit
bad15ffe
authored
Feb 07, 2020
by
张宇
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
patch process_single_request
parent
a46dbd94
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
359 additions
and
28 deletions
+359
-28
__init__.py
adapter/rpcd/__init__.py
+128
-1
settings.py
courier/settings.py
+11
-3
types.py
extension/types.py
+2
-0
views.py
message/views.py
+30
-3
gaia_client.py
rpc/gaia_client.py
+6
-0
auth.py
rpc_framework/auth.py
+77
-0
authentication.py
rpc_framework/authentication.py
+49
-0
context.py
rpc_framework/context.py
+1
-1
exceptions.py
rpc_framework/exceptions.py
+25
-13
interceptors.py
rpc_framework/interceptors.py
+13
-3
models.py
rpc_framework/models.py
+13
-0
views.py
rpc_framework/views.py
+4
-4
No files found.
adapter/rpcd/__init__.py
View file @
bad15ffe
# -*- coding: utf-8 -*-
import
json
import
logging
import
os
import
traceback
import
uuid
from
django.conf
import
settings
from
gm_logging.internal.instance
import
request_logging_guard_maker
from
gm_rpcd.internals.common
import
now_str
from
gm_rpcd.internals.configuration.model
import
Config
,
environ
,
from_property
from
gm_rpcd.internals.configuration.model
import
Config
,
environ
,
\
from_property
from
gm_rpcd.internals.configuration.model_base
import
literal
,
xml_text
,
xml_text_list
,
\
DefaultConfigPropertyWrapper
,
EnvironmentConfigProperty
from
gm_rpcd.internals.context
import
Context
from
gm_rpcd.internals.dispatcher
import
json_encode_with_length
from
gm_rpcd.internals.dynamic_scopes
import
dynamic_scope
,
Keys
from
gm_rpcd.internals.protocol.request
import
Request
,
\
dump_request_to_json_value
from
gm_rpcd.internals.protocol.response
import
FaultResponse
,
SuccessResponse
,
\
response_to_v1_json_value
,
SystemErrorResponse
from
gm_rpcd.internals.protocol.response_extras
import
\
make_method_not_found_response
from
gm_rpcd.internals.utils
import
strict_check_json_value
from
gm_tracer.context
import
current_tracer
from
rpc_framework.exceptions
import
RPCViewBaseException
DISPATCHER
=
None
...
...
@@ -77,6 +95,112 @@ class DjangoRpcdConfig(Config):
return
os
.
path
.
join
(
self
.
log_dir
,
'gm_rpcd_request_error.log'
)
def
process_single_request
(
self
,
request
):
assert
isinstance
(
request
,
Request
)
tracer
=
current_tracer
()
method_function
=
self
.
_method_table
.
get_method_function
(
request
.
method
)
if
not
method_function
:
return
make_method_not_found_response
(
request
)
request_json_value
=
dump_request_to_json_value
(
request
)
request_json_str
=
json
.
dumps
(
request_json_value
,
ensure_ascii
=
False
)
now
=
now_str
()
request_info
=
self
.
_request_info_extractor
(
request
)
log_id
=
request_info
.
log_id
span_id
=
getattr
(
request_info
,
'span_id'
,
''
)
parent_span_id
=
getattr
(
request_info
,
'parent_span_id'
,
''
)
gm_request_id
=
getattr
(
request_info
,
'gm_request_id'
,
''
)
log_locating_info
=
'log_id={} span_id={} parent_span_id={}'
.
format
(
log_id
,
span_id
,
parent_span_id
)
with
request_logging_guard_maker
(
request_info
)
as
guard
:
context
=
Context
(
request
=
request
,
request_info
=
request_info
,
logger
=
guard
.
logger
,
helios_base_invoker
=
self
.
_helios_base_invoker
,
)
with
dynamic_scope
.
set
(
Keys
.
CONTEXT
,
context
),
dynamic_scope
.
set
(
Keys
.
REQUEST_INFO
,
request_info
):
try
:
result
=
method_function
(
**
request
.
params
)
strict_check_json_value
(
result
)
response
=
SuccessResponse
(
request_id
=
request
.
request_id
,
result
=
result
,
)
except
RPCViewBaseException
as
e
:
guard
.
set_errno
(
e
.
code
)
response
=
FaultResponse
(
request_id
=
request
.
request_id
,
error
=
{
# 最终相应为: {'error': '..','message': '..', 'data': ''}
'code'
:
e
.
code
,
'message'
:
e
.
message
,
}
)
except
Exception
as
e
:
guard
.
set_errno_unexpected
()
if
self
.
_raven_client
:
self
.
_raven_client
.
captureException
(
tags
=
{
'log_id'
:
log_id
,
'gm_request_id'
:
gm_request_id
,
'span_id'
:
span_id
,
'parent_span_id'
:
parent_span_id
,
},
extra
=
{
'log_id'
:
log_id
,
'span_id'
:
span_id
,
'parent_span_id'
:
parent_span_id
,
'request'
:
request_json_value
,
'gm_request_id'
:
gm_request_id
,
}
)
format_exc
=
traceback
.
format_exc
()
log_message
=
json
.
dumps
({
'timestamp'
:
now
,
'gm_request_id'
:
gm_request_id
,
'log_locating_info'
:
log_locating_info
,
'format_exc'
:
format_exc
,
'request_json_str'
:
request_json_str
,
},
ensure_ascii
=
False
)
self
.
_request_error_logger
.
error
(
log_message
)
from
gm_rpcd.internals.configuration.model
import
config
if
config
.
is_develop_mode
:
debug_message
=
'{}
\n
request = {}'
.
format
(
format_exc
,
request_json_str
,
)
else
:
debug_message
=
None
response
=
SystemErrorResponse
(
message
=
'Unexpected exception on server side. {}'
.
format
(
log_locating_info
),
debug_message
=
debug_message
,
)
if
tracer
:
# tracer.add_annotation({'error': time.time()})
tracer
.
add_binary_annotation
({
'error'
:
'true'
,
'exc.info'
:
format_exc
,
'request_json_str'
:
request_json_str
,
})
self
.
_request_logger
.
info
(
json
.
dumps
({
'timestamp'
:
now
,
'gm_request_id'
:
gm_request_id
,
'log_locating_info'
:
log_locating_info
,
'request_json_value'
:
json_encode_with_length
(
request_json_value
),
'response_json_value'
:
json_encode_with_length
(
response_to_v1_json_value
(
response
)),
},
ensure_ascii
=
False
))
return
response
def
setup_rpcd
():
logger
=
logging
.
getLogger
(
'django.start'
)
logger
.
info
(
'****** setup rpcd ******'
)
...
...
@@ -91,6 +215,9 @@ def setup_rpcd():
from
gm_rpcd.internals
import
configuration
configuration
.
__dict__
[
'config'
]
=
config_wrapper
from
gm_rpcd.internals.dispatcher
import
Dispatcher
Dispatcher
.
process_single_request
=
process_single_request
####################### end PATCH ##########################
from
gm_rpcd.internals.initializations
import
initialize
...
...
courier/settings.py
View file @
bad15ffe
...
...
@@ -20,7 +20,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY
=
'
d2#)2cd!efrj@to&45yn=+=82-b*&of3i*&fxgfq
%
v53h1&1qx'
SECRET_KEY
=
'
fl-lv3j^czg(dupo@hbs(+_+djby9zelwt&rh71@b1x*ptmj4#(^'
# gaia dev
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG
=
True
...
...
@@ -34,10 +34,11 @@ INSTALLED_APPS = [
'django.contrib.admin'
,
'django.contrib.auth'
,
'django.contrib.contenttypes'
,
#
'django.contrib.sessions',
'django.contrib.sessions'
,
'django.contrib.messages'
,
# 'django.contrib.staticfiles',
'api'
'api'
,
'rpc_framework'
]
MIDDLEWARE
=
[
...
...
@@ -275,3 +276,9 @@ ES_SEARCH_TIMEOUT = '10s'
DATABASE_ROUTERS
=
[
'courier.db_routers.MessageRouter'
]
MESSAGE_DB_NAME
=
'default'
MESSAGE_SLAVE_DB_NAME
=
'slave'
# AUTHENTICATION_BACKENDS = (AUTH_WE_CHAT_BACKEND, AUTH_DJANGO_DEFAULT_BACKEND)
AUTH_USER_USING_GAIA_DB
=
True
# SESSION_ENGINE = 'django.contrib.sessions.backends.db'
# SESSION_ENGINE = 'rpc_framework.auth'
SESSION_SERIALIZER
=
'django.contrib.sessions.serializers.PickleSerializer'
# fuck gaia
\ No newline at end of file
extension/types.py
View file @
bad15ffe
...
...
@@ -4,3 +4,4 @@ from gm_types.utils.enum import Enum, unique
class
Error
(
int
,
Enum
):
PARAMS_INVALID
=
(
10001
,
'非法参数'
)
AUTH_FAILED
=
(
40300
,
'登录信息不正确或没有权限'
)
\ No newline at end of file
message/views.py
View file @
bad15ffe
# -*- coding: utf-8 -*-
from
typing
import
List
,
Dict
,
Optional
from
django.conf
import
settings
from
six
import
string_types
import
dateutil
from
django.db.models
import
Q
...
...
@@ -11,9 +12,12 @@ from adapter.old_system import bind_prefix
from
adapter.rpcd.exceptions
import
RPCPermanentError
from
api.models.message
import
ConversationUserStatus
from
rpc
import
gaia_client
from
rpc.gaia_client
import
get_doctor_basic_info
,
get_single_doctor_basic_info
from
rpc_framework
import
exceptions
from
rpc_framework.context
import
RPCViewContext
from
rpc_framework.decorators
import
rpc_view
,
interceptor_classes
from
rpc_framework.interceptors
import
CalleeParametersInterceptor
from
rpc_framework.interceptors
import
CalleeParametersInterceptor
,
\
SessionUserInterceptor
from
search.utils
import
search_conversation_from_es
from
services.unread.stat
import
UserUnread
...
...
@@ -236,6 +240,29 @@ def message_conversation_list_v3(user_ids: List[int],
@rpc_view
(
'message/conversation/can_send'
)
@interceptor_classes
([
CalleeParametersInterceptor
])
@interceptor_classes
([
CalleeParametersInterceptor
,
SessionUserInterceptor
])
def
check_can_send_message
(
context
:
RPCViewContext
,
target_uid
:
str
)
->
Dict
:
return
{
'a'
:
'b'
}
user
=
context
.
user
# doctor_info = get_single_doctor_basic_info(user.id)
#
# target_user_id = doctor_info.get('user_id')
# print('target_user_id:', target_user_id)
# raise exceptions.NotFoundException
# if not target_user_id:
# raise 26872687
# target_doctor = get_doctor_by_user_id(target_user.id)
#
# if doctor or target_doctor:
# return {'can_send': True}
#
# user_follow = user.fans.filter(follow=target_user, bond=True).exists()
# target_follow = target_user.fans.filter(follow=user, bond=True).exists()
#
# if user_follow and target_follow:
# return {'can_send': True}
# if target_user.person.id.hex == settings.KEFU_PERSION_ID:
# return {'can_send': True}
return
{
'can_send'
:
False
}
rpc/gaia_client.py
View file @
bad15ffe
...
...
@@ -44,6 +44,12 @@ def get_doctor_basic_info(doctor_ids: List[str]) -> List[Dict]:
)
.
unwrap
()
def
get_single_doctor_basic_info
(
doctor_id
:
str
)
->
Dict
:
return
get_rpc_remote_invoker
()[
'api/doctor/basic_info'
](
doctor_ids
=
[
doctor_id
]
)
.
unwrap
()[
0
]
def
batch_get_doctor_info_by_user_ids
(
user_ids
:
List
[
int
])
->
Dict
:
return
get_rpc_remote_invoker
()[
'api/batch_get_doctor_info_by_user_ids'
](
user_ids
=
user_ids
,
...
...
rpc_framework/auth.py
0 → 100644
View file @
bad15ffe
# -*- coding: utf-8 -*-
from
importlib
import
import_module
from
typing
import
Type
import
django
from
django.conf
import
settings
from
django.contrib.auth
import
BACKEND_SESSION_KEY
,
load_backend
,
\
HASH_SESSION_KEY
,
SESSION_KEY
from
django.db
import
models
from
django.utils.crypto
import
constant_time_compare
from
rpc_framework.context
import
RPCViewContext
from
rpc_framework.models
import
GaiaUser
from
django.contrib.sessions.models
import
Session
as
DjangoSession
from
django.contrib.sessions.backends.db
import
SessionStore
as
DjangoSessionStore
# class Session(DjangoSession):
# objects = models.Manager().db_manager(using='gaia')
# class SessionStore(DjangoSessionStore):
# @classmethod
# def get_model_class(cls):
# Avoids a circular import and allows importing SessionStore when
# django.contrib.sessions is not in INSTALLED_APPS.
# return Session
def
get_user
(
context
):
"""
Return the user model instance associated with the given request session.
If no user is retrieved, return an instance of `AnonymousUser`.
"""
if
getattr
(
settings
,
'AUTH_USER_USING_GAIA_DB'
,
False
):
return
get_user_using_gaia_db
(
context
)
else
:
return
get_user_using_passport_service
(
context
)
def
get_session_store_class
()
->
Type
[
django
.
contrib
.
sessions
.
backends
.
db
.
SessionStore
]:
# django SessionMiddleware
engine
=
import_module
(
settings
.
SESSION_ENGINE
)
return
engine
.
SessionStore
def
get_user_using_gaia_db
(
context
:
RPCViewContext
):
from
django.contrib.auth.models
import
AnonymousUser
user
=
None
try
:
session_store_class
=
get_session_store_class
()
session
=
session_store_class
(
context
.
_context
.
session_id
)
user_id
=
GaiaUser
.
_meta
.
pk
.
to_python
(
session
[
SESSION_KEY
])
backend_path
=
session
[
BACKEND_SESSION_KEY
]
except
KeyError
:
pass
else
:
if
backend_path
in
settings
.
AUTHENTICATION_BACKENDS
:
backend
=
load_backend
(
backend_path
)
user
=
backend
.
get_user
(
user_id
)
# Verify the session
if
hasattr
(
user
,
'get_session_auth_hash'
):
session_hash
=
session
.
get
(
HASH_SESSION_KEY
)
session_hash_verified
=
session_hash
and
constant_time_compare
(
session_hash
,
user
.
get_session_auth_hash
()
)
if
not
session_hash_verified
:
session
.
flush
()
user
=
None
return
user
or
AnonymousUser
()
def
get_user_using_passport_service
(
context
):
pass
rpc_framework/authentication.py
0 → 100644
View file @
bad15ffe
"""
Provides various authentication policies.
"""
from
__future__
import
unicode_literals
class
BaseAuthentication
(
object
):
"""
All authentication classes should extend BaseAuthentication.
"""
def
authenticate
(
self
,
request
):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
raise
NotImplementedError
(
".authenticate() must be overridden."
)
def
authenticate_header
(
self
,
request
):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
class
SessionAuthentication
(
BaseAuthentication
):
"""
Use Django's session framework for authentication.
"""
def
authenticate
(
self
,
context
):
"""
Returns a `User` if the request session currently has a logged in user.
Otherwise returns `None`.
"""
# Get the session-based user from the underlying HttpRequest object
user
=
getattr
(
context
.
context
,
'user'
,
None
)
# Unauthenticated, CSRF validation not required
if
not
user
or
not
user
.
is_active
:
return
None
# self.enforce_csrf(context)
# CSRF passed with authenticated user
return
(
user
,
None
)
\ No newline at end of file
rpc_framework/context.py
View file @
bad15ffe
...
...
@@ -82,7 +82,7 @@ class RPCViewContext(object):
instance, ensuring that it is available to any middleware in the stack.
"""
self
.
_user
=
value
self
.
_
reques
t
.
user
=
value
self
.
_
contex
t
.
user
=
value
@property
def
request
(
self
)
->
Optional
[
Request
]:
...
...
rpc_framework/exceptions.py
View file @
bad15ffe
# -*- coding: utf-8 -*-
from
abc
import
ABCMeta
,
abstractmethod
from
typing
import
Sequence
from
typing
import
Sequence
,
Optional
,
Union
,
Dict
,
List
from
gm_rpcd.internals.exceptions
import
RPCDFaultException
from
pydantic
import
ValidationError
,
create_model
from
pydantic.error_wrappers
import
ErrorList
from
pydantic.error_wrappers
import
ErrorList
,
ErrorWrapper
from
extension.types
import
Error
...
...
@@ -22,29 +22,41 @@ def _check_methods(C, *methods):
return
True
class
RPCViewBaseException
(
metaclass
=
ABCMeta
):
class
RPCViewBaseException
(
Exception
,
metaclass
=
ABCMeta
):
code
:
int
message
:
str
data
:
Optional
[
Union
[
Dict
,
List
]]
__slots__
=
()
@classmethod
def
__subclasshook__
(
cls
,
C
):
if
cls
is
RPCViewBaseException
:
return
_check_methods
(
C
,
"as_rpc
d_fault
"
)
return
_check_methods
(
C
,
"as_rpc
_view_exception
"
)
return
NotImplemented
@abstractmethod
def
as_rpcd_fault
(
self
):
return
RPCDFaultException
(
error
=
self
.
error
,
message
=
self
.
message
)
RequestErrorModel
=
create_model
(
"Request"
)
class
CalleeTypeHintValidationError
(
ValidationError
):
def
__init__
(
self
,
errors
:
Sequence
[
ErrorList
])
->
None
:
return
super
()
.
__init__
(
errors
,
RequestErrorModel
)
class
CalleeTypeHintValidationError
(
RPCViewBaseException
):
code
=
Error
.
PARAMS_INVALID
message
=
''
@classmethod
def
from_error_wrapper_list
(
cls
,
errors
:
List
[
ErrorWrapper
]):
validation_error
=
ValidationError
(
errors
,
RequestErrorModel
)
self
=
cls
()
self
.
message
=
validation_error
.
json
()
return
self
class
AuthenticationFailed
(
RPCViewBaseException
):
code
=
Error
.
AUTH_FAILED
message
=
Error
.
getDesc
(
Error
.
AUTH_FAILED
)
class
NotFoundException
(
RPCViewBaseException
):
code
=
1404
message
=
"Not Found"
# default_message = "Not Found"
def
as_rpcd_fault
(
self
):
return
RPCDFaultException
(
code
=
Error
.
PARAMS_INVALID
,
message
=
self
.
json
())
rpc_framework/interceptors.py
View file @
bad15ffe
...
...
@@ -4,6 +4,7 @@ from abc import ABCMeta, abstractmethod
from
copy
import
deepcopy
from
typing
import
Type
,
Any
,
List
,
Optional
,
Dict
,
Tuple
from
django.utils.functional
import
SimpleLazyObject
from
pydantic
import
BaseModel
,
BaseConfig
,
MissingError
from
pydantic.error_wrappers
import
ErrorWrapper
from
pydantic.fields
import
ModelField
,
Required
,
FieldInfo
,
SHAPE_SINGLETON
,
\
...
...
@@ -11,7 +12,7 @@ from pydantic.fields import ModelField, Required, FieldInfo, SHAPE_SINGLETON, \
from
pydantic.schema
import
get_annotation_from_field_info
from
pydantic.utils
import
lenient_issubclass
from
rpc_framework
import
params
from
rpc_framework
import
params
,
auth
,
exceptions
from
rpc_framework.context
import
RPCViewContext
from
rpc_framework.exceptions
import
CalleeTypeHintValidationError
from
rpc_framework.inspector
import
get_typed_signature
...
...
@@ -165,7 +166,6 @@ def check_parameters_fit_signature(
else
:
values
[
field
.
name
]
=
deepcopy
(
field
.
default
)
continue
print
(
value
,
values
)
v_
,
errors_
=
field
.
validate
(
value
,
values
,
loc
=
(
"body"
,
field
.
alias
))
if
isinstance
(
errors_
,
ErrorWrapper
):
errors
.
append
(
errors_
)
...
...
@@ -182,5 +182,15 @@ class CalleeParametersInterceptor(Interceptor):
callee_field_list
=
get_callee_field_list
(
rpc_view
.
callee
)
validated_values
,
errors
=
check_parameters_fit_signature
(
callee_field_list
,
context
.
request
.
params
)
if
errors
:
raise
CalleeTypeHintValidationError
(
errors
)
raise
CalleeTypeHintValidationError
.
from_error_wrapper_list
(
errors
)
return
True
class
SessionUserInterceptor
(
Interceptor
):
def
intercept
(
self
,
context
:
RPCViewContext
,
rpc_view
:
RPCView
)
->
bool
:
user
=
auth
.
get_user
(
context
)
context
.
user
=
user
if
context
.
user
:
return
True
raise
exceptions
.
AuthenticationFailed
()
rpc_framework/models.py
0 → 100644
View file @
bad15ffe
# -*- coding: utf-8 -*-
from
django.contrib.auth.models
import
User
from
django.db
import
models
class
BaseUser
(
User
):
class
Meta
(
User
.
Meta
):
db_table
=
'auth_user'
class
GaiaUser
(
User
):
# objects = models.Manager().db_manager(using='gaia')
pass
\ No newline at end of file
rpc_framework/views.py
View file @
bad15ffe
...
...
@@ -14,10 +14,11 @@ def set_rollback():
def
exception_handler
(
exc
,
wrapped_context
)
->
None
:
if
issubclass
(
exc
.
__class__
,
exceptions
.
RPCViewBaseException
):
set_rollback
()
raise
exc
.
as_rpcd_fault
()
# type: RPCDFaultException
if
isinstance
(
exc
,
exceptions
.
RPCViewBaseException
):
raise
exc
elif
issubclass
(
exc
.
__class__
,
exceptions
.
RPCViewBaseException
):
raise
exc
.
as_rpc_view_exception
()
return
None
...
...
@@ -76,7 +77,6 @@ class RPCView(RPCAbstractView):
result
=
handler
(
context
,
*
args
,
**
kwargs
)
except
Exception
as
exc
:
print
(
'error::'
,
exc
,
type
(
exc
))
result
=
self
.
handle_exception
(
exc
)
self
.
result
=
self
.
finalize_response
(
context
,
result
,
*
args
,
**
kwargs
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment