| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- // package contract -- контракт каждого протона и нейтрона
- package contract
- import (
- "os"
- . "gitp78su.ipnodns.ru/svi/kern/v4/lev0/helpers"
- )
- // isContractDisabled -- признак включённости контрактов
- // По умолчанию определяется переменной окружения IS_CONTRACT (любое непустое значение включает контракты).
- var isContractDisabled = os.Getenv("IS_CONTRACT") == ""
- // stage -- значение переменной окружения STAGE
- // Если STAGE != "prod", контракты всегда включены.
- var stage = os.Getenv("STAGE")
- // Contract -- контракт каждого протона и нейтрона
- // T -- тип контекста, передаваемого в пред-, ин- и постусловия
- type Contract struct {
- // fnPre -- предусловие: должно быть истинно перед выполнением операции
- fnPre func()
- // fnPost -- постусловие: должно быть истинно после выполнения операции
- fnPost func()
- }
- // ContractOpt -- опция для настройки контракта
- type ContractOpt func(*Contract)
- // ContractOptPre -- задать предусловие
- func ContractOptPre(fn func()) ContractOpt {
- return func(sf *Contract) {
- sf.fnPre = fn
- }
- }
- // ContractOptPost -- задать постусловие
- func ContractOptPost(fn func()) ContractOpt {
- return func(sf *Contract) {
- sf.fnPost = fn
- }
- }
- // NewContract -- создать новый контракт с опциями
- func NewContract(opts ...ContractOpt) *Contract {
- sf := &Contract{}
- for _, opt := range opts {
- opt(sf)
- }
- return sf
- }
- // Wrap -- оборачивает произвольную функцию выполнением контракта
- // Схема вызова: Pre(ctx) -> fn(ctx) -> Post(ctx).
- // Если соответствующее условие не задано, оно пропускается.
- func (sf *Contract) Wrap(fn func()) func() {
- Hassert(fn != nil, "Contract[T].Wrap(): fn==nil")
- // В непроизводственных окружениях (STAGE != "prod") всегда оборачиваем
- if stage == "prod" && isContractDisabled {
- // В prod оборачиваем только если явно включены контракты
- return fn
- }
- return func() {
- if sf.fnPre != nil {
- sf.fnPre()
- }
- fn()
- if sf.fnPost != nil {
- sf.fnPost()
- }
- }
- }
|