第一次参加幼儿园的家长开放日活动,老师带着做早操,活力满满~
Algorithm
本周选择的算法题是:Destroying Asteroids。
impl Solution {
pub fn asteroids_destroyed(mass: i32, mut asteroids: Vec<i32>) -> bool {
asteroids.sort_unstable();
let mut mass = mass as i64;
for asteroid in asteroids {
if asteroid as i64 > mass {
return false;
} else {
mass += asteroid as i64;
}
}
true
}
}
Review
Clean Code vs. Performant Code
梳理下作者的结论:
- 不干净的代码性能更好,哪怕是像 Swift 这种在编译器层面深度优化过的语言也是
- clean code 更合适扩展,便于写出好维护、好协作的代码
- 不要盲目遵守某种教条,这不是选择 clean or not clean 的理由
- 在没有严格限制性能的场景,优先选择 clean code;系统开始工作后,关注它的性能表现,并在开始优化之前进行测量
作者的结论基于文中给出的测试用例,但还是有不严谨的地方,比如给 class 增加 final 修饰符后可以做到全都要,添加 final 后其函数在运行期调用时避免了 vtable 式的查表,又保留了 clean 原则。
其次,编程语言、编译器在不断发展的过程中越来越注重零成本抽象,以 Rust 为例,我们让 ChatGPT 解释一下:
因此,我同意 “从 clean code 开始,其次是关注它的性能表现” 的观点,通常我会很在意代码是不是干净整洁的,如果有例外,应该清楚地记录为什么使用晦涩的、不易阅读的代码,我们努力构建的东西要有能提供长期支撑的底座。
Tip
用远程覆盖掉本地分支的内容:
git reset --hard origin/master
Share
为 dify 添加 ldap 支持
dify 是一个开源的 LLMOps 平台,可以快速创建 AI-Native 应用。但目前 dify 还是一个半成品的状态,邮箱邀请是一个假功能:
支持的登录方式也很有限:
看 dify 团队的描述,一时半会也等不到,好在 dify 代码清晰、结构一目了然,不用花太多功夫就能在本地添加对 ldap 的支持,接下来我们描述一下具体方向,涉及到:
- 后端
- 前端
- Docker
首先是后端部分。
后端
由于 dify 的后端技术栈是 python + flask,我们先添加对应的 python 包:
python-ldap==3.4.3
接着在 api/services 目录下增加一个新的 ldap_service.py:
#!/usr/bin/python3
# -*-coding:utf-8-*-
__author__ = "your_name"
import ldap
LDAP_SERVER = 'ldap://host'
BASE_DN = 'base dn to search in'
OBJECT_TO_SEARCH = 'cn=%s'
ATTRIBUTES_TO_SEARCH = ['cn', 'mail']
def ldap_login(username, password):
"""
用于进行 ldap 登录验证;如果验证失败,则返回 None。
"""
try:
connect = ldap.initialize(LDAP_SERVER)
connect.set_option(ldap.OPT_REFERRALS, 0) # to search the object and all its descendants
connect.simple_bind_s(f"{OBJECT_TO_SEARCH % username},{BASE_DN}", password)
result = connect.search_s(BASE_DN, ldap.SCOPE_SUBTREE, OBJECT_TO_SEARCH % username, ATTRIBUTES_TO_SEARCH)
except ldap.INVALID_CREDENTIALS:
return None
object = result[0][1]
name = object["cn"][0].decode()
email = object["mail"][0].decode()
return {
"email": email,
"name": name,
}
接着修改 LoginApi.py 文件,调整 post 实现为:
@setup_required
def post(self):
"""Authenticate user and login."""
parser = reqparse.RequestParser()
# parser.add_argument('email', type=email, required=True, location='json')
parser.add_argument('email', required=True, location='json')
parser.add_argument('password', type=valid_password, required=True, location='json')
parser.add_argument('remember_me', type=bool, required=False, default=False, location='json')
args = parser.parse_args()
# todo: Verify the recaptcha
try:
account = AccountService.authenticate(args['email'], args['password'])
except services.errors.account.AccountLoginError:
return {'code': 'unauthorized', 'message': 'Invalid name or password'}, 401
try:
TenantService.switch_tenant(account)
except Exception:
raise AccountNotLinkTenantError("Account not link tenant")
flask_login.login_user(account, remember=args['remember_me'])
AccountService.update_last_login(account, request)
# todo: return the user info
return {'result': 'success'}
这个方法要做的事情其实很简单,就是干掉 email 校验。
然后修改 account_service.py 文件,引入 ldap_service:
from .ldap_service import ldap_login
并调整 authenticate 实现为:
@staticmethod
def authenticate(name: str, password: str) -> Account:
"""authenticate account with name and password"""
ldap_object = ldap_login(name, password)
if ldap_object is None:
raise AccountLoginError('Invalid name or password.')
account = Account.query.filter_by(name=name).first()
if not account:
email = ldap_object["email"]
name = ldap_object["name"]
account = RegisterService.register(email, name, password)
if not account:
raise AccountLoginError('Invalid name or password.')
if account.status == AccountStatus.BANNED.value or account.status == AccountStatus.CLOSED.value:
raise AccountLoginError('Account is banned or closed.')
if account.status == AccountStatus.PENDING.value:
account.status = AccountStatus.ACTIVE.value
account.initialized_at = datetime.utcnow()
db.session.commit()
# if account.password is None or not compare_password(password, account.password, account.password_salt):
# raise AccountLoginError('Invalid name or password.')
return account
不再和数据库中的 account 进行对比,取而代之的是总是通过 ldap 发起网络验证。
后端部分就完成了。
前端
前端部分更容易,只需要修改 web/app/signin 登录页面的表单:
- 注释掉 handleEmailPasswordLogin 里的 email 校验
- 将表单中的 {t(‘login.email’)} 修改为 {t(‘login.name’)}
其他地方不用动。
Docker
因为修改了源码,需要重新构建镜像文件。首先是修改用于构建 api 镜像的 Dockerfile,将:
...
RUN pip install -r requirements.txt
...
修改为:
RUN apt-get install -y libsasl2-dev python-dev libldap2-dev libssl-dev
RUN pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
一方面是安装 python-ldap 所需的依赖,另一方面是设置镜像站点以加速安装过程。
The python-ldap is based on OpenLDAP, so you need to have the development files (headers) in order to compile the Python module. If you’re on Ubuntu, the package is called
libldap2-dev
.https://stackoverflow.com/questions/4768446/i-cant-install-python-ldap
web 镜像也同理,将:
RUN npm install
修改为:
RUN npm install --sentrycli_cdnurl=https://cdn.npmmirror.com/binaries/sentry-cli --loglevel verbose
整个过程就算是完成了。
最后用 docker build -t tag_name .
构建完镜像后,把 tag_name 更新到项目根目录下的 docker/docker-compose.yaml 中即可。
Have Fun~!