147 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			V
		
	
	
| module onecontext
 | |
| 
 | |
| import context
 | |
| import sync
 | |
| import time
 | |
| 
 | |
| // canceled is the error returned when the cancel function is called on a merged context
 | |
| pub const canceled = error('canceled context')
 | |
| 
 | |
| struct OneContext {
 | |
| mut:
 | |
| 	ctx        context.Context
 | |
| 	ctxs       []context.Context
 | |
| 	done       chan int
 | |
| 	err        IError = none
 | |
| 	err_mutex  sync.Mutex
 | |
| 	cancel_fn  context.CancelFn
 | |
| 	cancel_ctx context.Context
 | |
| }
 | |
| 
 | |
| // merge allows to merge multiple contexts
 | |
| // it returns the merged context
 | |
| pub fn merge(ctx context.Context, ctxs ...context.Context) (context.Context, context.CancelFn) {
 | |
| 	mut background := context.background()
 | |
| 	cancel_ctx, cancel := context.with_cancel(mut &background)
 | |
| 	mut octx := &OneContext{
 | |
| 		done: chan int{cap: 3}
 | |
| 		ctx: ctx
 | |
| 		ctxs: ctxs
 | |
| 		cancel_fn: cancel
 | |
| 		cancel_ctx: cancel_ctx
 | |
| 	}
 | |
| 	go octx.run()
 | |
| 	return context.Context(octx), context.CancelFn(cancel)
 | |
| }
 | |
| 
 | |
| pub fn (octx OneContext) deadline() ?time.Time {
 | |
| 	mut min := time.Time{}
 | |
| 
 | |
| 	if deadline := octx.ctx.deadline() {
 | |
| 		min = deadline
 | |
| 	}
 | |
| 
 | |
| 	for ctx in octx.ctxs {
 | |
| 		if deadline := ctx.deadline() {
 | |
| 			if min.unix_time() == 0 || deadline < min {
 | |
| 				min = deadline
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if min.unix_time() == 0 {
 | |
| 		return none
 | |
| 	}
 | |
| 
 | |
| 	return min
 | |
| }
 | |
| 
 | |
| pub fn (octx OneContext) done() chan int {
 | |
| 	return octx.done
 | |
| }
 | |
| 
 | |
| pub fn (mut octx OneContext) err() IError {
 | |
| 	octx.err_mutex.@lock()
 | |
| 	defer {
 | |
| 		octx.err_mutex.unlock()
 | |
| 	}
 | |
| 	return octx.err
 | |
| }
 | |
| 
 | |
| pub fn (octx OneContext) value(key context.Key) ?context.Any {
 | |
| 	if value := octx.ctx.value(key) {
 | |
| 		return value
 | |
| 	}
 | |
| 
 | |
| 	for ctx in octx.ctxs {
 | |
| 		if value := ctx.value(key) {
 | |
| 			return value
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return none
 | |
| }
 | |
| 
 | |
| pub fn (mut octx OneContext) run() {
 | |
| 	mut wrapped_ctx := &octx.ctx
 | |
| 	if octx.ctxs.len == 1 {
 | |
| 		mut first_ctx := &octx.ctxs[0]
 | |
| 		octx.run_two_contexts(mut wrapped_ctx, mut first_ctx)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	octx.run_multiple_contexts(mut wrapped_ctx)
 | |
| 	for mut ctx in octx.ctxs {
 | |
| 		octx.run_multiple_contexts(mut &ctx)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| pub fn (octx OneContext) str() string {
 | |
| 	return ''
 | |
| }
 | |
| 
 | |
| pub fn (mut octx OneContext) cancel(err IError) {
 | |
| 	octx.cancel_fn()
 | |
| 	octx.err_mutex.@lock()
 | |
| 	octx.err = err
 | |
| 	octx.err_mutex.unlock()
 | |
| 	if !octx.done.closed {
 | |
| 		octx.done <- 0
 | |
| 		octx.done.close()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| pub fn (mut octx OneContext) run_two_contexts(mut ctx1 context.Context, mut ctx2 context.Context) {
 | |
| 	go fn (mut octx OneContext, mut ctx1 context.Context, mut ctx2 context.Context) {
 | |
| 		octx_cancel_done := octx.cancel_ctx.done()
 | |
| 		c1done := ctx1.done()
 | |
| 		c2done := ctx2.done()
 | |
| 		select {
 | |
| 			_ := <-octx_cancel_done {
 | |
| 				octx.cancel(onecontext.canceled)
 | |
| 			}
 | |
| 			_ := <-c1done {
 | |
| 				octx.cancel(ctx1.err())
 | |
| 			}
 | |
| 			_ := <-c2done {
 | |
| 				octx.cancel(ctx1.err())
 | |
| 			}
 | |
| 		}
 | |
| 	}(mut &octx, mut &ctx1, mut &ctx2)
 | |
| }
 | |
| 
 | |
| pub fn (mut octx OneContext) run_multiple_contexts(mut ctx context.Context) {
 | |
| 	go fn (mut octx OneContext, mut ctx context.Context) {
 | |
| 		octx_cancel_done := octx.cancel_ctx.done()
 | |
| 		cdone := ctx.done()
 | |
| 		select {
 | |
| 			_ := <-octx_cancel_done {
 | |
| 				octx.cancel(onecontext.canceled)
 | |
| 			}
 | |
| 			_ := <-cdone {
 | |
| 				octx.cancel(ctx.err())
 | |
| 			}
 | |
| 		}
 | |
| 	}(mut &octx, mut &ctx)
 | |
| }
 |