app/app.go
func Swap(app1, app2 *App, cnameOnly bool) error {
	a1Routers := app1.GetRouters()
	a2Routers := app2.GetRouters()
	if len(a1Routers) != 1 || len(a2Routers) != 1 {
		return errors.New("swapping apps with multiple routers is not supported")
	}
	r1, err := router.Get(a1Routers[0].Name)
	if err != nil {
		return err
	}
	r2, err := router.Get(a2Routers[0].Name)
	if err != nil {
		return err
	}
	defer func(app1, app2 *App) {
		rebuild.RoutesRebuildOrEnqueue(app1.Name)
		rebuild.RoutesRebuildOrEnqueue(app2.Name)
		app1.GetRoutersWithAddr()
		app2.GetRoutersWithAddr()
	}(app1, app2)
	err = r1.Swap(app1.Name, app2.Name, cnameOnly)
	if err != nil {
		return err
	}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	app1.CName, app2.CName = app2.CName, app1.CName
	updateCName := func(app *App, r router.Router) error {
		return conn.Apps().Update(
			bson.M{"name": app.Name},
			bson.M{"$set": bson.M{"cname": app.CName}},
		)
	}
	err = updateCName(app1, r1)
	if err != nil {
		return err
	}
	return updateCName(app2, r2)
}
func Swap(app1, app2 *App, cnameOnly bool) error {
	a1Routers := app1.GetRouters()
	a2Routers := app2.GetRouters()
	if len(a1Routers) != 1 || len(a2Routers) != 1 {
		return errors.New("swapping apps with multiple routers is not supported")
	}
	r1, err := router.Get(a1Routers[0].Name)
	if err != nil {
		return err
	}
	r2, err := router.Get(a2Routers[0].Name)
	if err != nil {
		return err
	}
	defer func(app1, app2 *App) {
		rebuild.RoutesRebuildOrEnqueue(app1.Name)
		rebuild.RoutesRebuildOrEnqueue(app2.Name)
		app1.GetRoutersWithAddr()
		app2.GetRoutersWithAddr()
	}(app1, app2)
	err = r1.Swap(app1.Name, app2.Name, cnameOnly)
	if err != nil {
		return err
	}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	app1.CName, app2.CName = app2.CName, app1.CName
	updateCName := func(app *App, r router.Router) error {
		return conn.Apps().Update(
			bson.M{"name": app.Name},
			bson.M{"$set": bson.M{"cname": app.CName}},
		)
	}
	err = updateCName(app1, r1)
	if err != nil {
		return err
	}
	return updateCName(app2, r2)
}
// Swap calls the Router.Swap and updates the app.CName in the database.