func deliverRemote(addrInfo *resolver.AddressInfo, msgID string, header *message.Header) error {
	rs := container.Instance.GetResolveService()

	_, err := message.GetRetryInfo(message.SectionProcessing, msgID)
	if err == nil {
		rs.ClearRoutingCacheEntry(addrInfo.RoutingID)
	}

	routingInfo, err := rs.ResolveRouting(addrInfo.RoutingID)
	if err != nil {
		logrus.Warnf("cannot find routing ID %s for %s. Retrying.", addrInfo.RoutingID, header.To.Addr)
		MoveToRetryQueue(msgID)
		return err
	}

	logrus.Debugf("Message %s is remote, transferring to %s", msgID, routingInfo.Routing)

	t, err := processTicket(*routingInfo, *addrInfo, header, msgID)
	if err != nil {
		return err
	}

	c, err := getClient(*routingInfo)
	if err != nil {
		logrus.Warning("cannot create API: ", err)
		return err
	}

	// parallelize uploads
	g := new(errgroup.Group)

	g.Go(func() error {
		logrus.Tracef("uploading header for ticket %s", t.ID)
		return c.UploadHeader(*t, header)
	})

	g.Go(func() error {
		catalogPath, err := message.GetPath(message.SectionProcessing, msgID, "catalog")
		if err != nil {
			return err
		}

		catalogData, err := ioutil.ReadFile(catalogPath)
		if err != nil {
			return err
		}

		logrus.Tracef("uploading catalog for ticket %s", t.ID)
		return c.UploadCatalog(*t, catalogData)
	})

	messageFiles, err := message.GetFiles(message.SectionProcessing, msgID)
	if err != nil {
		_ = c.DeleteMessage(*t)
		return err
	}

	for _, messageFile := range messageFiles {
		g.Go(uploadBlockFromFile(c, t, messageFile))
	}

	// Wait until all are completed
	if err := g.Wait(); err != nil {
		logrus.Debugf("Error while uploading message %s: %s", msgID, err)
		_ = c.DeleteMessage(*t)
		return err
	}

	// All done, mark upload as completed
	logrus.Tracef("message completed for ticket %s", t.ID)
	err = c.CompleteUpload(*t)
	if err != nil {
		return err
	}

	h, err := hash.NewFromHash(addrInfo.Hash)
	if err == nil {
		_ = dispatcher.DispatchRemoteDelivery(*h, header, msgID)
	}

	// Remove local message from processing queue
	return message.RemoveMessage(message.SectionProcessing, msgID)
}
// deliverRemote uploads a message to a remote mail server. For this to work it first needs to fetch a
// ticket from that server. Either that ticket is supplied, or we need to do proof-of-work first before
// we get the ticket. Once we have the ticket, we can upload the message to the server in the same way
// we upload a message from a client to a server.
deliverRemote uploads a message to a remote mail server. For this to work it first needs to fetch a
ticket from that server. Either that ticket is supplied, or we need to do proof-of-work first before
we get the ticket. Once we have the ticket, we can upload the message to the server in the same way
we upload a message from a client to a server.
// deliverRemote uploads a message to a remote mail server . For this to work it first needs to fetch a // ticket from that server . Either that ticket is supplied or we need to do proof - of - work first before // we get the ticket . Once we have the ticket we can upload the message to the server in the same way // we upload a message from a client to a server .
func deliverRemote(addrInfo *resolver.AddressInfo, msgID string, header *message.Header) error {
	rs := container.Instance.GetResolveService()
	_, err := message.GetRetryInfo(message.SectionProcessing, msgID)
	if err == nil {
		rs.ClearRoutingCacheEntry(addrInfo.RoutingID)
	}
	routingInfo, err := rs.ResolveRouting(addrInfo.RoutingID)
	if err != nil {
		logrus.Warnf("cannot find routing ID %s for %s. Retrying.", addrInfo.RoutingID, header.To.Addr)
		MoveToRetryQueue(msgID)
		return err
	}
	logrus.Debugf("Message %s is remote, transferring to %s", msgID, routingInfo.Routing)
	t, err := processTicket(*routingInfo, *addrInfo, header, msgID)
	if err != nil {
		return err
	}
	c, err := getClient(*routingInfo)
	if err != nil {
		logrus.Warning("cannot create API: ", err)
		return err
	}
	g := new(errgroup.Group)
	g.Go(func() error {
		logrus.Tracef("uploading header for ticket %s", t.ID)
		return c.UploadHeader(*t, header)
	})
	g.Go(func() error {
		catalogPath, err := message.GetPath(message.SectionProcessing, msgID, "catalog")
		if err != nil {
			return err
		}
		catalogData, err := ioutil.ReadFile(catalogPath)
		if err != nil {
			return err
		}
		logrus.Tracef("uploading catalog for ticket %s", t.ID)
		return c.UploadCatalog(*t, catalogData)
	})
	messageFiles, err := message.GetFiles(message.SectionProcessing, msgID)
	if err != nil {
		_ = c.DeleteMessage(*t)
		return err
	}
	for _, messageFile := range messageFiles {
		g.Go(uploadBlockFromFile(c, t, messageFile))
	}
	if err := g.Wait(); err != nil {
		logrus.Debugf("Error while uploading message %s: %s", msgID, err)
		_ = c.DeleteMessage(*t)
		return err
	}
	logrus.Tracef("message completed for ticket %s", t.ID)
	err = c.CompleteUpload(*t)
	if err != nil {
		return err
	}
	h, err := hash.NewFromHash(addrInfo.Hash)
	if err == nil {
		_ = dispatcher.DispatchRemoteDelivery(*h, header, msgID)
	}
	return message.RemoveMessage(message.SectionProcessing, msgID)
}
func deliverRemote ( addrInfo * resolver . AddressInfo , msgID string , header * message . Header ) error { rs := container . Instance . GetResolveService ( ) _ , err := message . GetRetryInfo ( message . SectionProcessing , msgID ) if err == nil { rs . ClearRoutingCacheEntry ( addrInfo . RoutingID ) } routingInfo , err := rs . ResolveRouting ( addrInfo . RoutingID ) if err != nil { logrus . Warnf ( " " , addrInfo . RoutingID , header . To . Addr ) MoveToRetryQueue ( msgID ) return err } logrus . Debugf ( " " , msgID , routingInfo . Routing ) t , err := processTicket ( * routingInfo , * addrInfo , header , msgID ) if err != nil { return err } c , err := getClient ( * routingInfo ) if err != nil { logrus . Warning ( " " , err ) return err } g := new ( errgroup . Group ) g . Go ( func ( ) error { logrus . Tracef ( " " , t . ID ) return c . UploadHeader ( * t , header ) } ) g . Go ( func ( ) error { catalogPath , err := message . GetPath ( message . SectionProcessing , msgID , " " ) if err != nil { return err } catalogData , err := ioutil . ReadFile ( catalogPath ) if err != nil { return err } logrus . Tracef ( " " , t . ID ) return c . UploadCatalog ( * t , catalogData ) } ) messageFiles , err := message . GetFiles ( message . SectionProcessing , msgID ) if err != nil { _ = c . DeleteMessage ( * t ) return err } for _ , messageFile := range messageFiles { g . Go ( uploadBlockFromFile ( c , t , messageFile ) ) } if err := g . Wait ( ) ; err != nil { logrus . Debugf ( " " , msgID , err ) _ = c . DeleteMessage ( * t ) return err } logrus . Tracef ( " " , t . ID ) err = c . CompleteUpload ( * t ) if err != nil { return err } h , err := hash . NewFromHash ( addrInfo . Hash ) if err == nil { _ = dispatcher . DispatchRemoteDelivery ( * h , header , msgID ) } return message . RemoveMessage ( message . SectionProcessing , msgID ) }
deliverRemote uploads a message to a remote mail server.
deliverRemote uploads a message to a remote mail server .
// parallelize uploads // Wait until all are completed // All done, mark upload as completed // Remove local message from processing queue