github.com/Ptt-official-app/go-bbs@v0.12.0/pttbbs/pttbbs_write_article_connector.go (about)

     1  package pttbbs
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"os"
     7  	"time"
     8  
     9  	"github.com/Ptt-official-app/go-bbs"
    10  	"github.com/Ptt-official-app/go-bbs/filelock"
    11  )
    12  
    13  // CreateBoardArticleFilename get available filename for board with boardID, it will test is this filename not exist
    14  // And open a file to occupy this filename
    15  // Please see fhdr_stamp in pttbbs fhdr_stamp.c also
    16  func (c *Connector) CreateBoardArticleFilename(boardID string) (filename string, err error) {
    17  	var f *os.File
    18  	for {
    19  		dtime := time.Now().Unix()
    20  		// TOOD: Check 2038 Problem
    21  		filename = fmt.Sprintf("M.%d.A.%3.3X", dtime, rand.Intn(0x1000))
    22  		path, err := c.GetBoardArticleFilePath(boardID, filename)
    23  		if err != nil {
    24  			return filename, err
    25  		}
    26  
    27  		f, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
    28  		if err == nil {
    29  			break
    30  		}
    31  
    32  		// TODO: Should log if can not lock file in first time, is system loading too heavy?
    33  
    34  	}
    35  	f.Close()
    36  	return
    37  
    38  }
    39  
    40  // NewArticleRecord returns a new ArticleRecord given a filename, owner, date, title
    41  func (c *Connector) NewArticleRecord(filename, owner, date, title string) (bbs.ArticleRecord, error) {
    42  	ret := &FileHeader{
    43  		filename: filename,
    44  		owner:    owner,
    45  		date:     date,
    46  		title:    title,
    47  	}
    48  	return ret, nil
    49  }
    50  
    51  func (c *Connector) WriteBoardArticleFile(path string, content []byte) error {
    52  
    53  	f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
    54  	if err != nil {
    55  		return fmt.Errorf("openfile: %w", err)
    56  
    57  	}
    58  	defer f.Close()
    59  	err = filelock.Lock(f)
    60  	if err != nil {
    61  		// File is locked
    62  		return fmt.Errorf("filelock lock: %w", err)
    63  	}
    64  	defer filelock.Unlock(f)
    65  
    66  	if _, err := f.Write(content); err != nil {
    67  		return err
    68  	}
    69  	return nil
    70  
    71  }
    72  
    73  func (c *Connector) NewArticleRecordWithMap(args map[string]interface{}) (bbs.ArticleRecord, error) {
    74  
    75  	record := NewFileHeader()
    76  
    77  	owner, ok := args["owner"].(string)
    78  	if !ok {
    79  		return nil, fmt.Errorf("NewArticleRecord: owner must not be empty")
    80  	}
    81  	record.SetOwner(owner)
    82  
    83  	date, ok := args["date"].(string)
    84  	if !ok {
    85  		return nil, fmt.Errorf("NewArticleRecord: date must not be empty")
    86  	}
    87  	record.SetDate(date)
    88  
    89  	title, ok := args["title"].(string)
    90  	if !ok {
    91  		return nil, fmt.Errorf("NewArticleRecord: title must not be empty")
    92  	}
    93  	record.SetTitle(title)
    94  
    95  	boardID, ok := args["board_id"].(string)
    96  	if !ok {
    97  		return nil, fmt.Errorf("NewArticleRecord: board_id must not be empty")
    98  	}
    99  
   100  	filename := ""
   101  	dtime := time.Now().Unix()
   102  	rand.Seed(dtime)
   103  
   104  	var f *os.File
   105  	for {
   106  		filename = fmt.Sprintf("M.%d.A.%3.3X", dtime, rand.Intn(0x1000))
   107  		path, err := c.GetBoardArticleFilePath(boardID, filename)
   108  		if err != nil {
   109  			return nil, err
   110  		}
   111  
   112  		f, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
   113  		if err == nil {
   114  			break
   115  		}
   116  	}
   117  	defer f.Close()
   118  
   119  	record.SetFilename(filename)
   120  
   121  	err := filelock.Lock(f)
   122  	if err != nil {
   123  		// File is locked
   124  		return nil, err
   125  	}
   126  	defer filelock.Unlock(f)
   127  
   128  	data := fmt.Sprintf("作者: %s 看板: %s\n標題: %s \n時間: %s\n",
   129  		owner, boardID, title, date)
   130  
   131  	if _, err := f.Write([]byte(data)); err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	return record, nil
   136  }
   137  
   138  func (c *Connector) AddArticleRecordFileRecord(name string, article bbs.ArticleRecord) error {
   139  	a, ok := article.(*FileHeader)
   140  	if !ok {
   141  		return fmt.Errorf("article should be create with NewArticleRecord")
   142  	}
   143  	return AppendFileHeaderFileRecord(name, a)
   144  }