chatgpt网站登录后报Oops!, something went wrong

一直都用chrome浏览器登录chatgpt没有问题,今天突然报这个错,第一时间想到清理cookie缓存,但没有用,把所有缓存都清理也没有用,换chatgpt账号登录没有用,重启chrome、电脑,问题依然存在,换另一个帐号chrome登录(配置插件不一样),却是可以。

于是把有问题的帐号上的插件全部屏蔽,登录chatgpt正常,重新启用这些插件,换chatgpt帐号登录也正常了。 抽风的chatgpt,希望只是偶然,别让我天天这样搞。

发表在 杂项 | 留下评论

kex_exchange_identification: Connection closed by remote host 解决办法

遇到很奇葩的问题。

linux可以联网,可以访问google, 但ssh到某台外网服务器,却报

kex_exchange_identification: Connection closed by remote host

百思不得其解。甚至把交换机都换了一下,还是一样。

最后,换了一下科学上网的节点, 就ok了。  应该是一些节点的服务器屏蔽了22 端口的转发。 记录一下,希望对你有帮助 :)

发表在 技术, 杂项 | 留下评论

openwrt[解决]git: ‘remote-https’ is not a git command

在openwrt上得安装git-http

opkg remove git

opkg install git-http

opkg install ca-bundle

发表在 杂项 | 留下评论

解决transmission下载慢的问题

如果排除了网络问题、带宽问题,下载速度严重达不到带宽速度的,那最有可能是51413端口没有开通。

科普一下:

端口51413通常用于BitTorrent协议中的DHT(分布式哈希表)功能。DHT是一种用于查找和连接BitTorrent网络中的节点的技术。通过使用DHT,BitTorrent客户端可以在没有中央服务器的情况下查找和连接其他对等节点,从而提高了网络的分散性和鲁棒性。在BitTorrent中,端口51413是默认的DHT端口。DHT允许BitTorrent用户在下载或上传文件时查找其他用户,而无需依赖于传统的BitTorrent跟踪器(tracker)服务器。这有助于提高网络的效率和可用性。

检查端口是否通,可以在配置上面看

点击这个测试端口,显示端口不可连接,说明这个端口没有连通外网。

在路由器上配置端口转发:

重新测试端口:

这样速度就会有很大的提升。

发表在 技术, 杂项 | 留下评论

解决openwrt web打开时强制切换到https的问题

可能是以前开启过这个重定向选项,后来关闭了,它还是强制切换到https,后台简单重启一下uhttpd服务,还是不行。这应该是openwrt的一个bug。

解决办法:

登陆到openwrt后台

打开uhttpd服务的配置文件:

vim /etc/config/uhttpd

重启服务:

service uhttpd restart

发表在 技术, 杂项 | 留下评论

golang的errgroup简单用法介绍

errgroup是Go语言标准库golang.org/x/sync/errgroup中的一个包,用于管理一组goroutine的错误。它提供了一种优雅的方式来并发执行多个任务,并在其中任何一个任务返回错误时取消所有任务的执行。

errgroup类型通过errgroup.Group结构体表示,其中包含一个Wait方法和一个Go方法。

Wait方法用于等待所有goroutine完成并返回首个遇到的错误。如果没有错误发生,Wait方法将返回nil;如果有错误发生,它将返回首个遇到的错误。

Go方法用于启动一个新的goroutine,并将其添加到errgroup中。它接受一个函数参数作为goroutine的主体,并返回一个error类型的结果。如果该函数返回非nil的错误,则该错误将被视为整个errgroup的错误。

下面是一个简单示例,演示了如何使用errgroup来并发执行多个任务:

package main

import (
	"context"
	"fmt"
	"golang.org/x/sync/errgroup"
	"net/http"
)

func main() {
	g := new(errgroup.Group)

	// 启动第一个任务
	g.Go(func() error {
		resp, err := http.Get("https://www.example.com")
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// 执行任务逻辑...

		return nil
	})

	// 启动第二个任务
	g.Go(func() error {
		resp, err := http.Get("https://www.google.com")
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// 执行任务逻辑...

		return nil
	})

	// 等待所有任务完成
	if err := g.Wait(); err != nil {
		fmt.Println("At least one task failed:", err)
	} else {
		fmt.Println("All tasks completed successfully")
	}
}

在上面的示例中,我们创建了一个errgroup.Group实例,并使用Go方法启动了两个任务。然后,我们调用Wait方法等待所有任务完成。如果任何一个任务返回错误,Wait方法将返回该错误。

使用errgroup可以简化并发任务管理和错误处理的过程,使代码更加清晰和可读。请注意,errgroup并不会自动取消还在运行的任务,而是在首个错误出现时停止继续执行其他任务。因此,在使用errgroup时,需要确保每个任务都能够正确处理上下文的取消信号,以便及时终止任务的执行。

发表在 golang, 技术 | 留下评论

理解Go语言中Context的使用

在Go语言中,Context是一种用于管理一次请求的上下文环境的工具,它能够在不同的Goroutine之间传递请求特定的值、取消信号以及截止时间。Context可以帮助我们更好地控制并发请求,防止资源泄露以及过度的等待时间。让我们深入了解一下Go语言中Context的使用方法。

什么是Context

Context是Go语言中用于跟踪请求的上下文环境。它可以跨多个Goroutine传递请求范围的值,控制请求的截止时间,以及在需要时取消请求。Context是多协程安全的,它是Go中处理并发的重要工具,尤其是在高并发的网络应用程序中。

Context的基本用法

首先,我们需要导入”context”包。然后我们可以使用context.Background()来创建一个根Context,它是所有Context的起点。

package main

import (
	"context"
	"fmt"
)

func main() {
	ctx := context.Background()
	fmt.Println("Root Context:", ctx)
}

WithCancel

有时候,我们需要在某些条件满足时取消Context。使用context.WithCancel()函数可以创建一个带有取消信号的新Context。

func main() {
	parent := context.Background()
	ctx, cancel := context.WithCancel(parent)

	go func() {
		// 模拟取消操作
		cancel()
	}()

	select {
	case <-ctx.Done():
		fmt.Println("Context is canceled")
	}
}

WithDeadline

有时我们希望在一定时间内执行任务,超过这个时间就取消任务。可以使用context.WithDeadline()来创建一个带有截止时间的Context。

import (
	"time"
)

func main() {
	parent := context.Background()
	d := time.Now().Add(50 * time.Millisecond)
	ctx, cancel := context.WithDeadline(parent, d)

	select {
	case <-time.After(1 * time.Second):
		fmt.Println("Done")
	case <-ctx.Done():
		fmt.Println("Context is canceled")
	}
}

WithTimeout

context.WithTimeout()函数是context.WithDeadline()的一种简化形式,它创建一个在指定时间后自动取消的Context。

func main() {
	parent := context.Background()
	ctx, cancel := context.WithTimeout(parent, 50*time.Millisecond)
	defer cancel()

	select {
	case <-time.After(1 * time.Second):
		fmt.Println("Done")
	case <-ctx.Done():
		fmt.Println("Context is canceled")
	}
}

总结

在本文中,我们深入了解了Go语言中Context的用法。我们学习了如何创建一个基本的Context,以及如何使用WithCancelWithDeadlineWithTimeout等函数创建带有取消信号、截止时间或超时时间的Context。Context是Go语言中非常强大且实用的工具,特别适用于需要对并发请求进行细粒度控制的场景。使用Context可以有效地管理并发请求,避免资源泄露和过度等待时间,从而提高应用程序的性能和稳定性。

发表在 golang | 留下评论

领域驱动设计(DDD):将领域模型融入实际应用开发的艺术

在软件开发领域,领域驱动设计(Domain-Driven Design,简称DDD)是一种强调将业务领域的模型与实际应用程序开发过程相结合的方法。DDD有助于开发团队更好地理解和处理复杂的业务需求,从而创建出更加健壮和高质量的软件系统。

领域驱动设计的基本概念

领域驱动设计基于一些核心概念:

  1. 领域模型(Domain Model):领域模型是对业务领域的抽象表示。它包括实体(Entities)、值对象(Value Objects)、聚合根(Aggregate Roots)、仓储(Repositories)、工厂(Factories)、事件(Events)和服务(Services)等概念,用于捕捉业务领域的关键概念和规则。
  2. 限界上下文(Bounded Context):限界上下文定义了领域模型的边界,以确保模型的一致性和清晰性。一个大型应用通常会包含多个不同的限界上下文,每个上下文都有自己的领域模型。
  3. 实体(Entities)实体是具有唯一标识的领域对象,通常具有生命周期。在电子商务系统中,订单可以是一个实体,每个订单都有一个唯一的订单号。
  4. 值对象(Value Objects)值对象是没有唯一标识的领域对象,它们的相等性是根据属性的值来判断的。在电子商务系统中,产品可以是一个值对象,因为产品通常根据其属性(名称、价格等)来区分。
  5. 工厂(Factories)工厂是用于创建领域对象的机制。在电子商务系统中,可以创建一个订单工厂来创建新的订单。
  6. 事件(Events)事件表示领域中发生的重要事情。在电子商务系统中,订单状态改变事件可以表示当订单状态发生变化时的事件。
  7. 服务(Services)服务是用于执行领域之外的操作的组件。在电子商务系统中,可以创建一个支付服务来处理支付操作,因为支付通常涉及外部系统
  8. 仓库(Repository):仓库是用于管理领域对象的持久性的机制。它允许从数据库或其他持久性存储中检索和存储领域对象。

示例:电子商务系统中的DDD应用

1. 领域模型的构建

在电子商务系统中,我们有不同的领域模型。例如,我们有订单产品购物车等概念。通过DDD,我们可以创建这些领域模型并定义它们之间的关系。

// 实体(Entity)- 订单领域模型
type Order struct {
    ID        int
    Items     []OrderItem
    Status    OrderStatus
    Customer  Customer
    // 更多属性和方法
}

// 值对象(Value Object)- 产品领域模型
type Product struct {
    ID       int
    Name     string
    Price    float64
    Quantity int
    // 更多属性和方法
}

// 工厂(Factory)- 创建订单
func NewOrder(customer Customer) *Order {
    // 创建订单的逻辑...
}

// 事件(Event)- 订单状态改变事件
type OrderStatusChangedEvent struct {
    OrderID int
    NewStatus OrderStatus
    // 其他事件数据...
}

// 服务(Service)- 支付服务
type PaymentService struct {
    // 支付服务的依赖和方法...
}

2. 限界上下文的划分

在电子商务系统中,不同的领域模型可能在不同上下文中操作。例如,订单和产品管理是两个不同的限界上下文。这些上下文有自己的领域模型和语言,但它们可以相互通信。

3. 仓储的应用

仓储是用于处理领域对象的持久性的机制。在DDD中,仓储允许我们从数据库或其他持久性存储中检索和存储领域对象。

// 仓储接口
type OrderRepository interface {
    GetByID(id int) (*Order, error)
    Save(order *Order) error
}

// 实现订单仓储
type OrderRepositoryImpl struct {
    // 数据库连接或其他存储机制
}

func (r *OrderRepositoryImpl) GetByID(id int) (*Order, error) {
    // 从数据库中获取订单
    // 返回领域对象
}

func (r *OrderRepositoryImpl) Save(order *Order) error {
    // 将订单保存到数据库
}

4. 业务规则的体现

通过DDD,我们可以将业务规则嵌入到领域模型中。例如,在订单领域,我们可以定义一些规则,如订单必须包含有效的产品、订单状态必须合法等。这些规则可以通过领域模型的方法来执行。

// 订单领域模型的方法
func (o *Order) AddItem(product Product, quantity int) error {
    if quantity <= 0 {
        return errors.New("Quantity must be greater than 0")
    }
    // 检查其他规则...
    // 更新订单内容...
    return nil
}

5. 领域模型的测试

在DDD中,我们通常会编写测试来验证领域模型的行为是否符合业务规则。例如,我们可以编写测试来确保订单领域模型在添加商品时会正确处理各种情况。

func TestOrder_AddItem(t *testing.T) {
    order := &Order{}
    product := Product{ID: 1, Name: "Example Product", Price: 10.0, Quantity: 100}
    
    // 测试添加商品
    err := order.AddItem(product, 5)
    assert.Nil(t, err)
    
    // 测试非法数量
    err = order.AddItem(product, -1)
    assert.NotNil(t, err)
    // 其他测试...
}

仓储的应用是保持领域对象的持久性的关键,它们可以从数据库中检索领域对象并将其保存回数据库。这有助于确保领域模型的数据不会在系统重启或应用关闭时丢失。通过这个示例,我们可以更好地理解如何将DDD的核心概念融入实际应用程序开发中,以提高软件系统的质量和可维护性。

发表在 杂项 | 留下评论

谈邮件系统的治理:多种Failover策略的实现

随着电子邮件成为我们日常生活和业务通信的不可或缺的一部分,构建一个可靠的邮件系统变得至关重要。系统中的任何故障都可能导致邮件交付中断,这对业务运营和客户满意度都会带来负面影响。在这篇文章中,我们将介绍如何使用Golang构建一个邮件系统,并实施多种Failover策略,以确保系统的鲁棒性和可靠性。

Golang邮件系统基础

首先,我们需要一个基本的邮件系统框架。使用Golang,我们可以使用第三方库如net/smtpgo-gomail/gomail来构建这个系统。以下是一个简单的示例代码片段,用于发送邮件:

package main

import (
    "log"
    "net/smtp"
)

func main() {
    // 邮件服务器的地址和端口
    smtpServer := "smtp.example.com:587"

    // 发件人的认证信息
    auth := smtp.PlainAuth("", "your_username", "your_password", "example.com")

    // 构建邮件内容
    from := "[email protected]"
    to := []string{"[email protected]"}
    message := []byte("Subject: Hello\n\nThis is the email body.")

    // 发送邮件
    err := smtp.SendMail(smtpServer, auth, from, to, message)
    if err != nil {
        log.Fatal(err)
    }
}

Failover策略一:备用SMTP服务器

为了应对SMTP服务器故障,我们可以实施备用SMTP服务器的Failover策略。当主要SMTP服务器不可用时,我们将自动切换到备用SMTP服务器发送邮件。

package main

import (
    "log"
    "net/smtp"
)

func sendMailWithFailover(primaryServer, secondaryServer string, auth smtp.Auth, from string, to []string, message []byte) {
    err := smtp.SendMail(primaryServer, auth, from, to, message)
    if err != nil {
        log.Printf("Primary server error: %v. Trying secondary server...", err)
        err = smtp.SendMail(secondaryServer, auth, from, to, message)
        if err != nil {
            log.Printf("Secondary server error: %v. Mail delivery failed.", err)
        }
    }
}

Failover策略二:队列和重试

另一个重要的Failover策略是将邮件放入队列并定期重试发送。这可以帮助应对暂时的SMTP服务器故障或网络问题。

package main

import (
    "log"
    "net/smtp"
    "time"
)

func sendMailWithRetry(smtpServer string, auth smtp.Auth, from string, to []string, message []byte, maxRetries int) {
    for retry := 0; retry < maxRetries; retry++ {
        err := smtp.SendMail(smtpServer, auth, from, to, message)
        if err == nil {
            log.Printf("Email sent successfully.")
            return
        }
        log.Printf("Error sending email: %v. Retrying in 5 seconds...", err)
        time.Sleep(5 * time.Second)
    }
    log.Printf("Max retries reached. Mail delivery failed.")
}

结论

构建一个可靠的邮件系统需要仔细考虑Failover策略,以确保邮件的可靠交付。在本文中,我们使用Golang演示了两种Failover策略:备用SMTP服务器和队列/重试。实际系统可能需要更多功能,如邮件队列管理和监控。但这个示例可以帮助您开始构建一个稳健的邮件系统。

发表在 golang | 留下评论

7星坑狙射树枭单刷打法

千万别上野队车,大多没有好结果,浪费时间而已。他们知道用苍炎刃鬼,但不知道配合,也不知道配招,加速时间消耗而已,我附图4个苍鬼野队的下场。

言归正传,我用100级苍炎刃鬼单刷,配招:悔念剑,大晴天,清除之烟,剑舞。努力值加血和物攻,钛晶火,特性引火(千万别是碎甲),道具带密探斗篷(防对面三连箭附带的降防御效果)。

开局点支援加加防御,因为对面第一招是暗影爪,正常扣一半血,中要害基本你残了。支援优先度最高,必定是先加防御再中招,正常只扣三分之一不到。

第二招剑舞或者大晴天,对面第二招是清除buff,但速度比你快,所以是他先清除,你再开buff。之后连续用3次悔念剑,但到第二剑,你很可能挂了,期间它会用健美和剑舞,复活后打清除之烟,这时候你可以太晶化了,打一发剑舞,然后一直无脑悔念剑就行了。它基本上打不死你。死掉一次时间还是够的,牺牲一次是为了加快太晶化为火,避免中暗影爪。打倒它时间可能只剩下一回合的样子或者刚刚好用完。

好了,这就是我的单刷心得,祝各位游戏愉快,顺利破坑。

发表在 游戏 | 留下评论