JobServer

Landscape

services-job-server.svg

JobServer 包含 Schedulers 及 Workers。Scheduler 中包含一组 Scheduler 实例,用于定时调度 Job。Workers 包含了固定种类的 Worker 实例,每个实例独自工作。JobServer 用于创建、查询、更改 Job 状态,并持久化到 Store 中。
Worker 的实现通过向 JobServer 注册 Worker Generator 来实现。具体的实现不在开源项目中。同时,Worker 与 Scheduler 成对出现,均由使用者自己实现,因此,细节不能继续讨论。

  1. var accountMigrationInterface func(*Server) einterfaces.AccountMigrationInterface
  2. func RegisterAccountMigrationInterface(f func(*Server) einterfaces.AccountMigrationInterface) {
  3. accountMigrationInterface = f
  4. }

HTTPService

Landscape

services-http-service.svg

Core

首先创建基础的 Dialer 结构,并配置参数。

  1. dialContext := (&net.Dialer{
  2. Timeout: ConnectTimeout,
  3. KeepAlive: 30 * time.Second,
  4. }).DialContext

将基础的 DialContext 传入,进行增强后,返回新的 DialContext。

  1. func dialContextFilter(dial DialContextFunction, allowHost func(host string) bool, allowIP func(ip net.IP) bool) DialContextFunction {
  2. return func(ctx context.Context, network, addr string) (net.Conn, error) {
  3. host, port, err := net.SplitHostPort(addr)
  4. if err != nil {
  5. return nil, err
  6. }
  7. if allowHost != nil && allowHost(host) {
  8. return dial(ctx, network, addr)
  9. }
  10. ips, err := net.LookupIP(host)
  11. if err != nil {
  12. return nil, err
  13. }
  14. var firstErr error
  15. for _, ip := range ips {
  16. select {
  17. case <-ctx.Done():
  18. return nil, ctx.Err()
  19. default:
  20. }
  21. if allowIP == nil || !allowIP(ip) {
  22. continue
  23. }
  24. conn, err := dial(ctx, network, net.JoinHostPort(ip.String(), port))
  25. if err == nil {
  26. return conn, nil
  27. }
  28. if firstErr == nil {
  29. firstErr = err
  30. }
  31. }
  32. if firstErr == nil {
  33. return nil, AddressForbidden
  34. }
  35. return nil, firstErr
  36. }
  37. }

File Store

Landscape

services-file-store.svg

FileBackend 接口如下

  1. type FileBackend interface {
  2. TestConnection() *model.AppError
  3. Reader(path string) (ReadCloseSeeker, *model.AppError)
  4. ReadFile(path string) ([]byte, *model.AppError)
  5. FileExists(path string) (bool, *model.AppError)
  6. CopyFile(oldPath, newPath string) *model.AppError
  7. MoveFile(oldPath, newPath string) *model.AppError
  8. WriteFile(fr io.Reader, path string) (int64, *model.AppError)
  9. RemoveFile(path string) *model.AppError
  10. ListDirectory(path string) (*[]string, *model.AppError)
  11. RemoveDirectory(path string) *model.AppError
  12. }

Image Proxy

References

Landscape

services-image-proxy.svg

Details

LocalBackend 获取图片的处理,注意其中的 Headers。

  1. func (backend *LocalBackend) GetImage(w http.ResponseWriter, r *http.Request, imageURL string) {
  2. // The interface to the proxy only exposes a ServeHTTP method, so fake a request to it
  3. req, err := http.NewRequest(http.MethodGet, "/"+imageURL, nil)
  4. if err != nil {
  5. // http.NewRequest should only return an error on an invalid URL
  6. mlog.Error("Failed to create request for proxied image", mlog.String("url", imageURL), mlog.Err(err))
  7. w.WriteHeader(http.StatusBadRequest)
  8. w.Write([]byte{})
  9. return
  10. }
  11. w.Header().Set("X-Frame-Options", "deny")
  12. w.Header().Set("X-XSS-Protection", "1; mode=block")
  13. w.Header().Set("X-Content-Type-Options", "nosniff")
  14. w.Header().Set("Content-Security-Policy", "default-src 'none'; img-src data:; style-src 'unsafe-inline'")
  15. backend.impl.ServeHTTP(w, req)
  16. }